Compare commits

..
Author SHA1 Message Date
gozeros 1c933a8f19 sync snapshot from LAN repo (source tjlnew @ 9774c311) 2026-11-05 11:02:38 +08:00
1608 changed files with 15405 additions and 246258 deletions

No files matched your search

-58
View File
@@ -71,7 +71,6 @@ offline-backend-20260512/backend/.deer-flow/data/*.db-*
offline-backend-20260512/backend/.deer-flow/*
offline-backend-20260512/backend/.env
offline-backend-20260512/backend/.env.local
offline-backend-20260512/backend/.extensions_config.json.lock
offline-backend-20260512/start_backend.sh
offline-backend-20260512/stop_backend.sh
offline-backend-20260512/check_backend.sh
@@ -89,48 +88,12 @@ skills/
hermes-agent-main/
.gitignore
offline-backend-20260512/backend/tests/*
!offline-backend-20260512/backend/tests/test_large_file_safety.py
!offline-backend-20260512/backend/tests/test_account_authentication.py
# Seeder-owned Agent Skills are product source; keep them out of the broad
# runtime `skills/` ignore above.
!offline-backend-20260512/backend/app/gateway/routers/_*_seed_assets/skills/
!offline-backend-20260512/backend/app/gateway/routers/_*_seed_assets/skills/**
# Keep startup seed completeness and task-report conversion regressions versioned.
!offline-backend-20260512/backend/tests/test_seed_assets.py
!offline-backend-20260512/backend/tests/test_latency_diagnosis_seed.py
!offline-backend-20260512/backend/tests/test_query_slowdown_diagnosis_seed.py
!offline-backend-20260512/backend/tests/test_elasticsearch_offline_ops_seed.py
!offline-backend-20260512/backend/tests/test_task_report_convert.py
!offline-backend-20260512/backend/tests/test_migration_compatibility.py
# Keep the dedicated taskId + goPath history Gateway contract versioned.
!offline-backend-20260512/backend/tests/test_task_deeplink_threads_api.py
!offline-backend-20260512/backend/tests/test_thread_clear.py
# Keep project-scoped cross-conversation memory regressions versioned.
!offline-backend-20260512/backend/tests/test_analysis_project_memory.py
!offline-backend-20260512/backend/tests/test_analysis_project_memory_integration.py
!offline-backend-20260512/backend/tests/test_analysis_project_memory_runtime.py
!offline-backend-20260512/backend/tests/test_analysis_project_memory_store.py
# Keep answer-level feedback persistence, scoring, resolver, and migration regressions versioned.
!offline-backend-20260512/backend/tests/test_answer_feedback.py
# Keep wx common-agent category configuration regressions versioned.
!offline-backend-20260512/backend/tests/test_wx_common_agents.py
# Keep the built-in public-document seed regressions versioned.
!offline-backend-20260512/backend/tests/test_gongwen_agent_seed.py
!offline-backend-20260512/backend/tests/test_gongwen_documents.py
# Keep the openGauss URL/dialect/schema compatibility regression coverage versioned.
!offline-backend-20260512/backend/tests/test_gauss_database.py
!offline-backend-20260512/backend/tests/test_llmwiki_weknora.py
!offline-backend-20260512/backend/tests/test_llmwiki_knowledge_management.py
!offline-backend-20260512/backend/tests/test_llmwiki_smart_reasoning.py
!offline-backend-20260512/backend/tests/test_smart_reasoning_retrieval_middleware.py
!offline-backend-20260512/backend/tests/test_knowledge_retrieval_settings.py
!offline-backend-20260512/backend/tests/test_wiki_generation_config.py
!offline-backend-20260512/backend/tests/test_wiki_directory_constraints.py
!offline-backend-20260512/backend/tests/test_llmwiki_parent_directory_routing.py
!offline-backend-20260512/backend/tests/test_llmwiki_loading.py
!offline-backend-20260512/backend/tests/test_weknora_embed_script.py
!offline-backend-20260512/backend/tests/test_weknora_static.py
!offline-backend-20260512/backend/tests/test_llmwiki_advanced_retrieval.py
!offline-backend-20260512/backend/tests/test_knowledge_live_embedding.py
!offline-backend-20260512/backend/tests/test_health_auth_bypass.py
# Keep formal Word OOXML and embedded-font regression coverage versioned.
@@ -154,26 +117,17 @@ offline-backend-20260512/backend/tests/*
!offline-backend-20260512/backend/tests/test_llmwiki_local_index_repository.py
!offline-backend-20260512/backend/tests/test_llmwiki_vector_search.py
!offline-backend-20260512/backend/tests/test_llmwiki_wiki_sync.py
!offline-backend-20260512/backend/tests/test_llmwiki_incremental_sync_contract.py
!offline-backend-20260512/backend/tests/test_llmwiki_encoder_runtime.py
!offline-backend-20260512/backend/tests/test_external_llmwiki_search.py
!offline-backend-20260512/backend/tests/test_llmwiki_wiki_retrieval.py
!offline-backend-20260512/backend/tests/test_public_llmwiki_embed.py
# Keep assistant-source snapshot publication atomic across re-import jobs.
!offline-backend-20260512/backend/tests/test_assistant_snapshot_pointer_contract.py
# Deep-research reliability regression coverage.
!offline-backend-20260512/backend/tests/test_deep_research_persistence.py
!offline-backend-20260512/backend/tests/test_deep_research_event_sink.py
!offline-backend-20260512/backend/tests/test_deep_research_executor_reliability.py
!offline-backend-20260512/backend/tests/test_deep_research_start_job.py
!offline-backend-20260512/backend/tests/test_summarization_human_message.py
!offline-backend-20260512/backend/tests/test_llmwiki_title_ranking.py
!offline-backend-20260512/backend/tests/test_menu_overrides.py
!offline-backend-20260512/backend/tests/test_compact_menu_overrides.py
# Keep database-backed upload-policy, enforcement and bounded-preview regressions versioned.
!offline-backend-20260512/backend/tests/test_upload_policy.py
!offline-backend-20260512/backend/tests/test_uploads_policy_enforcement.py
!offline-backend-20260512/backend/tests/test_artifact_preview.py
# Independent enterprise-research persistence, HTTP and race regressions.
!offline-backend-20260512/backend/tests/test_enterprise_research_tasks.py
# Position-roundtable per-turn write/present cap (weak-model duplicate artifacts).
@@ -189,8 +143,6 @@ offline-backend-20260512/backend/tests/*
!offline-backend-20260512/backend/tests/test_workflow_runs.py
!offline-backend-20260512/backend/tests/test_workflow_concurrency.py
!offline-backend-20260512/backend/tests/test_workflow_schema_rebuild.py
# Per-account question recommendation preferences.
!offline-backend-20260512/backend/tests/test_user_preferences.py
# Writing-mode first-report pipeline enforcement regressions.
!offline-backend-20260512/backend/tests/test_writing_mode_report_middleware.py
!offline-backend-20260512/backend/tests/test_writing_rewrite_prompt.py
@@ -218,7 +170,6 @@ git-clone/
frontend-web/.offline-pack-build/
frontend-web/.offline-extract-test/
frontend-web-node_modules-offline-*.tar.gz
/deerflow-frontend-dist-*.zip
# Local dependency caches and backend scratch archives
/.pnpm-store/
@@ -237,19 +188,10 @@ docs/backups
# Frontend skills components must be tracked (excluded from the broad skills/ ignore above)
!frontend-web/src/components/workspace/skills/
# Built-in analysis mind-map skill is product source, not a per-user runtime skill.
!offline-backend-20260512/backend/skills/
offline-backend-20260512/backend/skills/*
!offline-backend-20260512/backend/skills/public/
offline-backend-20260512/backend/skills/public/*
!offline-backend-20260512/backend/skills/public/analysis-mindmap/
!offline-backend-20260512/backend/skills/public/analysis-mindmap/SKILL.md
# uv lockfile (not tracked per project preference)
offline-backend-20260512/backend/uv.lock
!offline-backend-20260512/backend/tests/test_wiki_package_roundtrip.py
!offline-backend-20260512/backend/tests/test_llmwiki_incremental_sync_scheduler.py
# Local-only scratch directory (not committed)
0622/
+1 -4
View File
@@ -90,16 +90,13 @@ The frontend (`frontend-web/`) is a React 19 + Vite SPA:
- **Pages**: `ChatPage` (thread chat), `AgentChatPage` (custom agent chat), `AgentsPage`/`NewAgentPage` (agent management), `ScheduledTasksPage`/`ScheduledTaskRunDetailPage` (scheduled tasks), `LightAppManagementPage`/`LightAppListPage`/`LightAppIframeView` (轻应用中心 — register/list/embed mini-apps)
- **AI 写作·对话版(对话驱动写作台)**: a **parallel new entry** beside the classic AI-writing page (classic page/routes untouched) — route `/page/canvas/ai-writing-chat`, sidebar 「问答管理 → 课题研究(对话版)」. Page `open-canvas/pages/AIWritingChatPage.tsx` reuses the engine (`AIWritingContext` + `useStream` + `AIWritingDraftPanel`); **idle keeps the classic setup layout** (`WritingSetupChat` + collapsible form) and switches to the chat workbench once writing starts; left panel `components/ai-writing-chat/WritingChatPanel.tsx` = **unified chronological feed** (`ChatFlowTimeline.tsx`, chat bubbles anchor-interleaved into the progress timeline so triggered events render below the user's message) + button-only intervention cards (`ChatInterventionCards.tsx`, inline textareas removed) + bottom unified smart composer. Intent resolution: frontend fast path + `POST /api/ai-writing/sessions/{id}/intent` → `deerflow/agents/ai_writing/intent_router.py` (per-pause action whitelist, high-cost confidence gates, payload cleaning); supports QA bypass, clarify follow-ups, control intents, and material-stage auto re-search + pending-intent resume. Tests `tests/test_ai_writing_intent.py`; plan doc `frontend-web/docs/ai-writing-对话驱动写作台-实现方案.md`.
- **轻应用中心 (Light App Center)**: a sibling of 任务管理 in the sidebar with two pages — 应用管理 (admin registers `window_open` or `iframe` mini-apps with a route-param builder: login params resolved from `localStorage.userInfo`, theme params literal) and 应用列表 (card grid of `window_open` apps, `window.open` launch). `iframe` apps are mounted under a chosen parent menu (XK/PG/TY/综合管理) and **dynamically injected into the sidebar** by `core/page-layout/use-sidebar-menu.ts` (`useSidebarMenuItems`), opening in the `LightAppIframeView` host. Client + React Query hooks in `strategy-components/api/light-apps.ts`; URL builder/constants in `strategy-components/lib/light-app.ts`. Backend: `/api/light-apps` (global/shared, admin-gated writes).
- **菜单管理 (Menu Management, admin defaults + personal layouts)**: `MenuManagementPage` (`pages/MenuManagementPage.tsx`) is available from「设置和更多」and the global Header account dropdown. Administrators edit the shared default menu; ordinary users edit only their own full/compact menu snapshot. For users with a saved snapshot, known node ids keep the personal `label`/`disabled`/`parentId`/`sortOrder` (or compact placement/order), while administrator defaults for node ids absent from that snapshot flow through—so newly-added code menus and iframe light apps follow the current default without overwriting older personal choices. Temporarily absent dynamic nodes are preserved when an unrelated personal edit is saved;「恢复默认」deletes only that user's snapshot. The static tree (`core/page-layout/sidebar-menu.ts`) remains the source of icons/routes and administrator defaults remain sparse per-node deltas. Merge/snapshot helpers live in `core/page-layout/menu-overrides.ts` and `compact-menu-overrides.ts`; full-menu writes carry the complete effective parent hierarchy for cycle/strict three-level validation while persisting only the sparse admin delta or full personal snapshot. Backend `/api/menu-overrides` uses `menu_overrides` (default) + `user_menu_override_configs` (per-user snapshot); `/api/compact-menu-overrides` uses `compact_menu_overrides` (type `A` / `B` defaults) + `user_compact_menu_override_configs` (per-user/type snapshots). Each website selects its compact type via `runtime-config.js` `VITE_COMPACT_MENU_TYPE`; `CompactToolbox` renders `toolbox` items.
- **菜单管理 (Menu Management, admin-only)**: an **overlay** over the static sidebar menu — `MenuManagementPage` (`pages/MenuManagementPage.tsx`, route `/page/strategy/admin/menu-management`, opened from the admin-only 「菜单管理」 item in the **bottom-left settings dropdown** of `components/page-sidebar.tsx`). Admins rename / 停用·启用 / reorder (↑↓ or @dnd-kit drag) / re-parent (horizontal drag **or** the edit dialog's 「移动到」parent selector) any node across 一级/二级/三级, **including injected iframe light-app nodes** (`light-app-<appId>`). The static tree (`core/page-layout/sidebar-menu.ts`) stays the source of icons/routes; only per-node deltas (`label`/`disabled`/`parentId`/`sortOrder`) persist to the backend. Merge logic in `core/page-layout/menu-overrides.ts` (`applyMenuOverrides`, applied in `use-sidebar-menu.ts` after light-app injection, before role filter; disabling a node hides its whole subtree) — strict **3-level cap** (`wouldExceedDepth`). Client `strategy-components/api/menu-overrides.ts`. Backend: `/api/menu-overrides` (global/shared; open read, admin atomic replace-all). **简介模式** uses a separate overlay: every compact workspace menu item can be placed in `sidebar`(左侧菜单)、`settings`(设置和更多)or `toolbox`(右侧工具箱); `CompactToolbox` (`components/workspace/compact-toolbox.tsx`, mounted by `PageRoutes.tsx`) opens only when the square right-edge trigger is clicked, then slides a compact, content-height right-side drawer over a backdrop above global dropdowns; configured items render top-to-bottom as centered square cards with a large icon above the label while the effective layout is compact. `/api/compact-menu-overrides` stores two independent sets (type `A` / `B`); each website picks one via `runtime-config.js` `VITE_COMPACT_MENU_TYPE`.
- **舆情分析智能体(前端虚拟智能体)**: 智能体管理页新增「舆情分析」类型 tab,固定一张虚拟智能体卡片(名称/简介可编辑,存 localStorage)。对话页 `pages/SentimentAgentChatPage.tsx`(路由 `agents/sentiment-analysis/chats/:thread_id`)复用普通问答布局 + `MessageList`,**输入框只有发送按钮**;问答经 Gateway `POST /api/sentiment-agent/stream` 转发外部 AG-UI 网关(不经过 LangGraph),会话仅存 sessionStorage。接口地址 + Basic Auth 在 `runtime-config.js` 配置(`VITE_SENTIMENT_AGENT_API_URL` / `_AUTH_USERNAME` / `_AUTH_PASSWORD`)并随请求传给后台;后台按传入地址转发、关闭 TLS 校验,失败时把完整错误回传。核心模块 `src/core/sentiment-agent/`。
- **简洁模式用户引导 (Compact-mode onboarding tour)**: 简洁模式(外观设置的「全量/简洁」= compact,无全局导航栏 + 页面侧边栏)新增 TDesign React `Guide` 组件驱动的分步引导。组件 `components/workspace/compact-mode-guide.tsx`(挂在 `ChatPage`):9 步 —— 欢迎弹窗(dialog 模式)→ 左侧功能导航 → 聊天记录 → 设置和更多 → 换肤 → 界面模式(切回全量)→ 常用提示词栏 → 提示词管理弹窗 → 输入框;高亮目标由各组件上的 `data-compact-guide` 标记定位(`workspace-nav-chat-list` / `recent-chat-list` / `workspace-nav-menu` / `appearance-controls` / `custom-prompt-menu.tsx` 的 `CustomPromptBar`(提示词栏,仅新对话落地态渲染)与其 `ManagePromptsDialog`(`prompt-dialog` 锚点)/ ChatPage 输入框容器),**启动时按目标是否存在过滤步骤**(如新用户无聊天记录、侧栏收起时自动剔除该步 —— Guide 对缺失元素会抛错,不能盲传)。**提示词管理弹窗步骤是动态目标**:弹窗平时不渲染,引导切到该步前先广播 `PROMPT_DIALOG_GUIDE_EVENT`(`custom-prompt-menu.tsx` 导出)让 `CustomPromptBar` 打开 `ManagePromptsDialog` 并**接管**(`owner: true` 期间 ESC/点遮罩不关闭,防止高亮目标消失导致 Guide 报错),轮询锚点真正挂载后才切步;离开该步 / 跳过 / 完成 / 中途卸载时以 `owner: false` 收回弹窗,4 秒打不开则跳过该步防卡死。**TDesign Guide × Radix 模态互操作**:Radix 模态弹窗打开时会把 `body` 置 `pointer-events:none`(滚动锁定),Guide 直接挂在 body 下的遮罩/高亮/弹层会一并继承失活(引导按钮点不动),`styles/tdesign-theme.css` 末尾对 `.t-guide__overlay/__highlight/__popup/__wrapper` 显式 `pointer-events:auto` 兜底。触发:① 自动 —— 简洁模式新对话落地页自动演示,直到用户显式点「完成」或「跳过」才写 localStorage `deerflow.compact-guide-finished` 记忆(浏览器级);**中途刷新/离开不记忆,下次进入还会再演示**。② 手动 —— 「设置和更多」下拉新增「界面使用引导」(该下拉仅存在于简洁模式工作区侧栏 footer):已在问答页时广播 `compact-guide:start` 窗口事件直接启动,否则写 sessionStorage 请求并导航 `/chats/new` 由挂载的引导消费(消费在定时器真正启动时才执行,规避 StrictMode effect 双跑吞请求)。`eligible` 排除 embed=1 / hideChrome=1 / chats_iframe / FORCE_COLLAPSED_SIDEBAR(无界)等同样无全局 chrome 的特殊环境;启动延迟 800ms 等侧栏宽度过渡稳定后再测量高亮框。
- **智能体使用引导 (Agent onboarding tour, 三段式)**: 智能体「浏览管理 → 创建与配置 → 发起问答」全流程分步引导,组件 `components/workspace/agents/agent-guide.tsx`(同一 TDesign `Guide` 封装模式,与简洁模式引导共享记忆语义:**仅显式点「完成/跳过」才写 localStorage** `deerflow.agent-guide.<stage>.finished`,中途刷新/离开不记忆)。**自动演示仅 create / chat 两段**(进智能体列表页不弹引导,点「创建智能体」进入新建页时才自动演示;list 段的 `AgentGuide` 传 `autoStart={false}`,只能由头部「使用引导」按钮手动触发)。三段各自挂载、各自记忆:① `list`(`agent-gallery.tsx`,/page/workspace/agents)——分区 Tabs、搜索排序、智能体卡片操作、右上「创建智能体」按钮;**完成/跳过就地结束(不跳转创建页,与 create 段无联动)**,最后一步仅提示进入创建页后会有配置引导;② `create`(`NewAgentPage.tsx`,/page/workspace/agents/new)——左侧对话式创建输入区、基本信息、运行模型+入库模板名、知识空间、SOUL.md、技能穿梭框、保存按钮(9 步);③ `chat`(`AgentChatPage.tsx`,agents/:id/chats)——左栏切换与历史、常用问题 chips、输入框(落地态/会话态两个挂点同一 `chat-input` 标记)、右侧详情面板;`eligible` 限定普通智能体对话页(`showAgentList && !isEmbedded && !taskCtxOn`,即排除通用问答原地嵌入与任务深链工作区),三段共用 `isAgentGuideEnvironment()` 排除 embed/hideChrome/无界环境。高亮锚点 `data-agent-guide`:列表页 `tabs`/`search`/`agent-card`(卡片+列表两种布局的根元素)/`new-agent-btn`,创建页 `create-chat-input`/`create-basic`/`create-model`/`create-knowledge`/`create-soul`/`create-skills`/`create-save-btn`,对话页 `chat-sidebar`/`chat-questions`/`chat-input`/`chat-detail`;同样**启动时按目标存在性过滤步骤**(新用户无卡片/无预设问题时自动剔除)。手动重放:三个页面头部各有「使用引导」按钮(列表页创建按钮左侧、创建页 header 右侧、对话页 header),广播 `agent-guide:start:<stage>` 窗口事件强制重放(忽略已看过记忆)。
- **敏感词管理 (Sensitive Word Management)**: configures the **展示层脱敏映射** (原始词 → 替换词). **Gated on the username `lqq`** (not the admin role) — `getAccountDisplayName().toLowerCase() === "lqq"` (username = email `@` prefix, else `user_id`, same as the profile page); the dropdown entry, the route guard, and the page-level guard all use this check. `src/lib/desensitize.ts` ships a frozen seed map `SEED_DESENSITIZE_MAP` (the deployment seed) plus a live mutable `DESENSITIZE_MAP` (initialized from the seed so `desensitize()` works before any fetch). `DesensitizeWordsLoader` (mounted in `App.tsx` `AppProviders`) fetches `/api/sensitive-words` on startup and, if non-empty, calls `replaceDesensitizeMap(...)` to make the backend config the source of truth (empty/failed → keep seed). Page `SensitiveWordsPage.tsx` (route `/page/strategy/admin/sensitive-words`, opened from the 「敏感词管理」 item in the **bottom-left settings dropdown** of `components/page-sidebar.tsx`, present in **both** full + collapsed sidebar modes) lists/adds/edits/启停/deletes words and saves the **whole set atomically** (replace-all); a 「导入种子词」 button merges any missing `SEED_DESENSITIZE_MAP` entries into the editor. Client + hooks in `strategy-components/api/sensitive-words.ts` (`wordsToMap` folds enabled rows into the runtime map). Backend: `/api/sensitive-words` (global/shared; open read, write allowed for admin **or** the `lqq` account), mirroring 菜单管理's store shape. **侧边栏 + 导航栏 menu labels are desensitized** at the data source: `useSidebarMenuItems`/`useActiveThirdLevel` (`core/page-layout/use-sidebar-menu.ts`) map every node's `label` through a desensitizer built **directly from the `/api/sensitive-words` query** (`makeDesensitizer(wordsToMap(words))`, falling back to the global seed `desensitize` while empty) — this sidesteps the `replaceDesensitizeMap` effect-timing race. Only `label` is rewritten; `path`/`id`/`icon` are untouched so routing/highlight are unaffected. All nav surfaces (`page-sidebar.tsx`, `page-sidebar-dark.tsx`, `page-sidebar-v1.tsx`, `strategy-components/Header.tsx`, `PageRoutes.tsx`) consume this hook and are covered; `MenuManagementPage` uses the raw tree so admins still edit real labels.
- **技能上下线 (Skill Availability, owner/admin)**: the global `Skill.enabled` flag is the online/offline switch. Taking a skill offline persists `skills.<name>.enabled=false` in `extensions_config.json` but does **not** delete its directory or remove it from existing agent/workflow configurations; the row remains visible and bringing it online restores those references. Administrators may toggle every skill from 「技能管理」; ordinary users may toggle only their own non-built-in `custom` skills from 「技能 → 技能列表 → 我的」. Offline skills must be absent from every model-facing skill catalogue (`lead` prompt, `search_skills`, `skill_list`, `skill_view`, subagents, AI writing/deep research/roundtable and Workflow run-start validation), from agent skill pickers, and from direct sandbox access: `read_file`/`ls`/`glob`/`grep`/`bash` reject offline, unknown, root-wide and category-wide `/mnt/skills` paths. The backend mutation is `PUT /api/skills/{name}`, authorizes either an administrator or the persisted owner of the target custom skill, patches the raw document so MCP placeholders and unrelated extension fields survive, uses atomic replacement when supported plus a Docker single-file-bind fallback, and refreshes the skill prompt cache. Launchers keep the runtime extensions file in a writable persisted directory. Existing agent/strategy-agent references stay visible as 「已下线」 and may be removed but not newly selected.
- **技能地址管理 (Skill Address Management, admin-only)**: 扫描运行中的技能(`skills/{public,custom}` 下所有 `.md`/`.py`)里的 **http(s) URL 与 IP/IP:端口**,按唯一地址聚合全部出现位置(跨 .md/.py),支持**批量替换**(如把 UAT 地址一次性改成生产)。主体抽成可复用组件 `SkillAddressesPanel`(`pages/SkillAddressesPage.tsx` 导出,默认导出 `SkillAddressesPage` 仍保留旧路由 `/page/strategy/admin/skill-addresses` 作直链回退),**作为「技能地址管理」标签页嵌入管理员「技能管理」页 `pages/AdminSkillsPage.tsx`**(该页加 Tabs:「技能列表」+「技能地址管理」;入口在「设置和更多」下拉的「技能管理」`workspace-nav-menu.tsx` → `/page/workspace/admin/skills`,不再单列于 `components/page-sidebar.tsx` 左下角设置下拉):打开自动扫描并带**进度条**(扫描逐技能 / 应用逐文件 X/N,应对 150+ 技能),URL/IP 类型过滤 + 搜索 + 「片段批量套用」(如所有 `uat.4.cn` → `prod.4.cn`)、每地址「替换为」输入框(可展开看 `file:line` 片段)、内联**预览**、**应用**、**多关键词检索**(空格分隔全部命中),以及**修改记录**面板——每次应用生成一条记录(显示时间/改了哪些地址 from→to/文件数/处数),可**针对单次记录回退**(二次确认)。client + NDJSON 流式解析在 `strategy-components/api/skill-addresses.ts`。后端 `/api/skill-addresses`(**仅管理员**):所有文件 IO 走 `asyncio.to_thread` 不阻塞事件循环;`GET /scan`(+`/scan/stream`)、`POST /preview`、`POST /apply`(+`/apply/stream`)、`GET /backups`、`POST /rollback/{id}`;**子串安全替换**(基于 token span,不会误伤子串)、`expected_total` 乐观锁(409)、写前自动磁盘备份到 `{skills_root}/.address-edits/`(同时写一份 `{id}.manifest.json` 记录本次替换明细,供修改记录展示)、应用后刷新技能系统提示缓存。纯引擎 `deerflow/skills/address_scan.py`,router `app/gateway/routers/skill_addresses.py`,tests `tests/test_skill_addresses.py`。范围仅运行中技能,不动 `deploy/minimal/skills/`。
- **按钮管理 (Task Button Management, admin-only)**: configures the **可配置跳转按钮** rendered in the left task panel of the task deep-link workspaces (rwfx / 3qfx / xdfx, see `TaskFxWorkspace`). Each button = `{business, label, linkType, target, appendTaskId, idParam, idKind, enabled, sortOrder}`; `linkType` is `url` (外链 `window.open`, optional append of `?{idParam}={id}` — **`idParam` is the editable query-param name**, e.g. `id`/`task_id`), `business` (内部切换到另一业务, reuses `resolveTaskDeeplinkTarget`, always task id), or `purpose` (弹出当前任务的「任务目的」表格 via the shared `TaskPurposeDialog`, no target — configurable for any page incl. xdfx). **`host`(宿主路由)** asks the embedding parent to navigate: `runTaskButton` sends `window.parent.postMessage({ type:'HOST_NAVIGATE', path, queryParams:{ [idParam]: Number(taskId) } }, hostOrigin)` — `target` is the host route, `appendTaskId`/`idParam` become numeric `queryParams` (task id, or action id when `idKind:"action"` — same selector as url buttons, xdfx only), origin from `runtime-config.js` `VITE_HOST_NAVIGATE_ORIGIN` (else ancestorOrigins/referrer; never `*`). **`idKind` (`task`/`action`) only matters for xdfx**: its deep-link `?taskId=` is an 行动id and the 任务id is resolved at login (`fetchTaskIdFromAction`) — `TaskContext` now also stashes the raw `actionId`, so a url **or host** button can append either (default `task`). Page `TaskButtonsPage.tsx` (route `/page/strategy/admin/task-buttons`, **admin-gated**, entry「按钮管理」in the bottom-left settings dropdown of `components/page-sidebar.tsx`, both full + collapsed modes) has per-business tabs, edits name/type/target/启停/排序/增删, saves the **whole set atomically** (replace-all), plus 「导入默认」 to merge code-seed defaults. **Seed/fallback** (like 敏感词管理): only when the whole table is empty (fresh deploy, never saved) do the workspace + page fall back to `defaultTaskButtons(cfg)` — rwfx's url buttons (编辑/下一步/3q详情) built from the **live** `/api/public/config/task-deeplink` plus cross-business switch buttons for **all three** businesses (each switches to the other two — rwfx→三情/行动, 3qfx→任务/行动, xdfx→任务/三情). Once saved, the store is the sole source of truth. The old hardcoded jump buttons were migrated out: `TaskFxWorkspace` no longer hardcodes 切换到三情分析, `TaskActionsPanel` keeps only the non-jump 清除记录, and `TaskPurposePanel` dropped its 3q详情 button (now configurable) **and defaults the 目的树 table to collapsed** (chevron toggle). Helpers `core/auth/task-buttons.ts` (`TaskButton`, `defaultTaskButtons`, `resolveTaskButtons`, `buttonsForBusiness`, `runTaskButton`), client+hooks `strategy-components/api/task-buttons.ts`. Backend: `/api/task-buttons` (global/shared; open read, admin replace-all), store `deerflow.persistence.task_buttons` (table `task_buttons`, auto-created by `create_all`), wired `app.state.task_button_store`. Tests: `tests/test_task_buttons.py`.
- **单智能体任务深链聊天记录(2026-10-19)**: `3qfx` / `rwfx` / `xdfx` 的会话历史使用独立 `task_deeplink_threads` 索引表及 `GET /api/task-deeplink-threads?task_id=&go_path=`,前端由 `useTaskDeeplinkThreads` 读取,不再筛选通用聊天列表。LangGraph thread/checkpoint 仍是消息权威数据;专用表仅按 `(task_id, go_path)` 定位 thread。`3qfx/rwfx` 按任务 id,`xdfx` 按 URL 原始行动 id;新 thread 写 `metadata.{taskRecordId,taskGoPath,thread_type:"task_deeplink"}` 并自动登记,通用最近对话默认隐藏。迁移 `20261019_01` 只建表、**不迁移/回填旧数据**。
- **上下文近 3 轮滑窗(管理员全局开关)**: 「设置 → 上下文管理」可开启 `system_settings.json -> conversation_context.recent_turn_window_enabled`(默认关闭;`GET/PUT /api/system-settings/conversation-context`,PUT 仅管理员)。开启后 `RecentTurnsMiddleware` 只改变单次模型请求,保留含当前轮在内的最近 3 个真实用户回合及其 assistant/tool 链;checkpoint 与前端完整聊天记录不删。该模式优先于聊天框「上下文压缩」,且不会调用摘要模型;关闭后沿用原压缩行为。实现 `deerflow/agents/middlewares/recent_turns_middleware.py`,回归 `tests/test_summarization_multiturn.py` / `tests/test_prompt_prefix.py`。
- **State**: TanStack Query for server state, context providers (`SubtasksProvider`, `ArtifactsProvider`, `PromptInputProvider`) scoped to `WorkspaceRoutes`
- **LLM streaming**: `@langchain/langgraph-sdk` streams messages from the backend via SSE
- **UI**: Radix UI primitives + TailwindCSS v4 + shadcn-style components in `src/components/ui/`
+3 -47
View File
@@ -1,40 +1,5 @@
# CLAUDE.md
## Retrieved files in chat (2026-10-07)
The shared `MessageGroup` renders `RetrievedFileList` below its reasoning/tool
timeline, so retrieved originals remain visible when old tool steps collapse and
do not depend on a model calling `present_files` or enabling reference mode.
The file list starts collapsed, keeps the latest retrieved file visible with the
total count, and expands the remaining files in reverse retrieval order.
`core/messages/retrieved-files.ts` derives these cards only from completed skill
invocations (a known skill tool name or a skill script path in an execution tool).
Generic reads, listings, report generation tools, uploads and outputs are excluded;
workspace paths require a structured retrieval/file container and exclude paths
written in the same message group. It accepts structured file links and WeKnora identifiers such as `knowledge_id` and
`document_file_name`. It handles JSON wrappers, MCP text blocks and bounded JSON
following console logs, deduplicates by file identity and caps one group at 100
files / 2,000 visited payload nodes. Do not extract file cards from assistant prose,
failed tool calls, arbitrary document text or `/mnt/skills` / host filesystem paths.
The admin-only Settings → Appearance switch「技能检索文件展示」persists globally as
`citation_display.retrieved_files_enabled` (default true). The existing citation-display
PUT endpoint enforces administrator authorization. The UI waits for the setting
before collecting files, shares its query cache, and refreshes active clients every
60 seconds/on stale window focus. Disabling it hides retrieved cards, not normal artifacts.
Thread files reuse the authorized artifact endpoints and uploaded-file reader;
knowledge files reuse the authorized LLMWiki original-file API and
`WeKnoraSourceDrawer`. `/api/llmwiki/sources/resolve` maps provider knowledge-base
ids to local mapping ids only after checking the viewer's existing read access.
External links use HTTP(S) only, credential-free fetches for
inline preview, and a native original-file link for download/fallback; never send
the DeerFlow bearer token to them. External download behavior depends on the
source's response headers and browser cross-origin rules. Unknown formats or
unavailable Office sidecars fall back to downloading the original. Public shares
use their existing file route and do not query private knowledge document APIs.
Closing the shared preview dialog aborts in-flight requests and releases blob URLs.
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
@@ -112,28 +77,23 @@ The **Lead Agent** (`deerflow/agents/lead_agent/`) is the single LangGraph graph
### Frontend
- **账号登录、自主注册与单点登录**:`/login` 提供用户名/邮箱与密码登录,`/register` 提供自主注册。管理员在「设置 → 登录与注册」管理 `system_settings.json.authentication` 的四个开关:账号密码登录、自主注册、单点登录(同一账号仅一处在线)默认关闭;既有外部系统免登 `sso_enabled` 默认开启。已保存配置保持不变。开启密码登录后,私有页面先经 `/api/v1/auth/me` 验证,后端 Gateway/LangGraph 同步拒绝旧免密 JWT;合法登录在 JWT 写入 `auth_method`。未设置个人密码的账号使用配置中的系统口令,未自定义时为 `123ewq`;修改密码也须验证当前个人密码或默认口令。开启 `single_session_enabled` 后,每次成功登录原子递增 `token_version`,旧会话下一次请求即失效;前端每 15 秒及窗口激活时检查并退出,失效页禁止自动重登录,避免互踢。关闭单处限制时允许多个登录会话。外部免登参数兼容 hash 前后两种位置(hash 参数优先)。公开配置 `GET /api/v1/auth/options`,管理员读写 `GET/PUT /api/system-settings/authentication`。个人信息下提供修改密码;`LoginWhitelistPage.tsx` 提供管理员重置。密码与口令共用,更新后旧密码/链接失效并撤销旧会话;当前用户改密或管理员重置自身须保存返回的新 Bearer token。新密码不在用户列表回传明文,管理员仅在本次重置后临时复制链接。注册与新建外部账号均为普通用户,禁止依据名称自动授予管理员权限。
The frontend (`frontend-web/`) is a React 19 + Vite SPA:
- **Routing**: React Router v7; top-level routes in `src/pages/PageRoutes.tsx`, workspace sub-routes in `src/pages/WorkspaceRoutes.tsx`
- **Pages**: `ChatPage` (thread chat), `AgentChatPage` (custom agent chat), `AgentsPage`/`NewAgentPage` (agent management), `ScheduledTasksPage`/`ScheduledTaskRunDetailPage` (scheduled tasks), `LightAppManagementPage`/`LightAppListPage`/`LightAppIframeView` (轻应用中心 — register/list/embed mini-apps)
- **普通问答地图可视化**: shared `MarkdownContent` recognizes only dedicated `map-json` fences and otherwise preserves the legacy Markdown/Streamdown path byte-for-byte. `components/workspace/visualizations/` validates the bounded map contract with Zod, lazy-loads MapLibre, and provides loading/error/text fallbacks so malformed or unreachable maps never blank the message. The lead-agent prompt emits `map-json` only when the user explicitly asks for a map; flowcharts and other graphics continue through the existing Markdown/Mermaid path. The raster tile template comes from the single post-build setting `runtime-config.js` → `VITE_MAP_TILE_URL` (Google by default); replace it with the intranet `{z}/{x}/{y}` endpoint for disconnected deployments.
- **HTML 成品离线绘图运行时**: 新生成的 `.html` 源码直接引用 Gateway `/api/public/html-runtime/` 下的浏览器版 `g6.min.js`、`echarts.min.js`、`leaflet.js/css` 和 `deerflow-runtime.js`;文件随后台源码存放于 `vendor/html-runtime/`,不再依赖前端 Vite/node_modules 产物或公网 CDN。`config.yaml -> html_runtime.base_url` 是写入新 HTML 的浏览器可访问绝对地址,`html_runtime.map_tile_url` 是地图网页模式读取的瓦片模板。设置 → 外观的管理员选项「HTML 地图」可选 `echarts`(本地 GeoJSON,`data-df-geo`,默认)或 `leaflet`(地图网页,`data-df-map`);运行时同时保留两种初始化,已生成页面不因切换失效。用户上传的栅格图若要作为页面背景,使用同一 Gateway 源下的签名地址 `/api/public/html-images/{token}` 写入 `background-image`。流程图使用 `data-df-flow` + G6(不用 Mermaid),图表使用 `data-df-chart`。普通问答保持独立:消息列表 `map-json` 继续由前端原逻辑渲染,普通流程图/图表仍走 Markdown/Mermaid。
- **HTML 成品离线绘图运行时**: 新生成的 `.html` 源码直接引用 Gateway `/api/public/html-runtime/` 下的浏览器版 `g6.min.js`、`echarts.min.js`、`leaflet.js/css` 和 `deerflow-runtime.js`;文件随后台源码存放于 `vendor/html-runtime/`,不再依赖前端 Vite/node_modules 产物或公网 CDN。`config.yaml -> html_runtime.base_url` 是写入新 HTML 的浏览器可访问绝对地址,`html_runtime.map_tile_url` 是初始化脚本读取的瓦片模板。流程图使用 `data-df-flow` + G6(不用 Mermaid),图表使用 `data-df-chart`,地图使用 Leaflet `data-df-map`。普通问答保持独立:消息列表 `map-json` 继续由前端原逻辑渲染,普通流程图/图表仍走 Markdown/Mermaid。
- **定时任务「JSON → HTML 模板填充」(模板数据转换器)**: a third scheduled-task execution mode. In the create/edit dialog (`ScheduledTasksPage.tsx`), selecting the built-in agent **「模板数据转换器」** (`execution_agent_name === "template-json-builder"`, `TEMPLATE_BUILDER_AGENT_ID`) reveals a 「HTML模板」 select (`useHtmlTemplates` → `GET /api/scheduled-tasks/html-templates`) + a **.json 上传** button (reads the file's text into the prompt box) and **hides** the 必须生成 HTML/Markdown switches (this mode always outputs HTML). The chosen template persists as `execution_context.template_config.template_id` (`TemplateFillConfig` in `core/scheduled-tasks/types.ts`). At run time the backend converts the source JSON (the task prompt) into that template's `DATA` structure, validates (retry-on-fail), fills the template, and stores an HTML page previewable via the existing run-detail HTML preview. The source can be **pure JSON, plain text, or text-with-embedded-JSON** — the backend pre-extracts any embedded JSON and the agent's `SOUL.md` maps it (or the plain text's semantics) to the template's schema skeleton. **Chat-page debug entry (only this agent's `AgentChatPage`)**: when `agent_id === "template-json-builder"`, the chat header shows a 「页面模板」 select + a 「渲染预览」 button — after a normal Q&A run, the button takes the **latest AI reply**, POSTs it to `POST /api/scheduled-tasks/template-fill/render` (`renderTemplateFill`), and pops a dialog rendering the filled HTML in a `sandbox="allow-scripts"` iframe plus the structure-validation status/errors/gaps — for debugging the agent's conversion effect without creating a scheduled task. Gated strictly on the agent id, so other agents' chat pages are untouched. See the backend CLAUDE.md「Template-fill mode」for the engine (`deerflow/runtime/scheduler/template_fill.py`), agent seed, dispatch, and the render API.
- **AI 写作·对话版(对话驱动写作台)**: a **parallel new entry** beside the classic AI-writing page (classic page/routes untouched) — route `/page/canvas/ai-writing-chat` (`OpenCanvasRoutes.tsx`), sidebar 「问答管理 → 课题研究(对话版)」. Page `open-canvas/pages/AIWritingChatPage.tsx` fully **reuses the engine** (`AIWritingContext` state machine + LangGraph `useStream`, `AIWritingHistoryProvider`, right-side `AIWritingDraftPanel`) but replaces the presentation: left = `components/ai-writing-chat/WritingChatPanel.tsx` (timeline + **button-only intervention cards** `ChatInterventionCards.tsx` — the five pause cards copied from `InterventionCard.tsx` with all inline textareas removed, confirm/action buttons kept — plus a bottom **unified smart composer**). Free text goes through two-level intent resolution (`open-canvas/api/ai-writing-intent.ts`): deterministic short-phrase fast path (确认/继续/重新搜索/重写大纲…; high-cost actions never fast-pathed) then `POST /api/ai-writing/sessions/{id}/intent` — the backend reads the graph checkpoint (authoritative pause point from the pending interrupt) and routes via `deerflow/agents/ai_writing/intent_router.py` (LLM + strict per-pause action whitelist aligned to the graph's real resume actions, confidence gates: finalize/force_finalize/覆盖式 re_search need ≥0.85 else clarify, payload key-whitelist cleaning). Results map to `submitIntervention`/control (暂停/继续/后台挂起)/QA bypass (`answer` rendered as a chat bubble, never touches graph state)/clarify (amber follow-up bubble with multi-turn context). **Two-state layout**: idle (未开始写作) renders the **classic setup experience unchanged** — `WritingSetupChat` + collapsible `AIWritingPanel` form under `WritingFormProvider` (same as `AIWritingPage`'s idle branch); once writing starts (or history view opens) it switches to the chat workbench. **Unified chronological feed** (`ChatFlowTimeline.tsx`): intent-layer chat bubbles are interleaved INTO the progress-event timeline by anchor (= `progressEvents.length` at message creation), so events triggered by a user message render **below** it (Google-AI-Studio-style single stream, not timeline-above/chat-below); composer-driven interventions suppress the duplicate 「我的要求」card (`suppressedRequirementIndices`). **素材不足自动续跑** only at `material_confirm` (the only pause the graph supports re-search from): needResearch caches the payload as a pending intent, submits `re_search + userQuery`, and auto-submits the pending intent when the new material-confirm pause arrives (cancellable pill). Stage chips + per-stage placeholder + 「当前交互对象」status badge. Backend tests `tests/test_ai_writing_intent.py`. Plan doc: `frontend-web/docs/ai-writing-对话驱动写作台-实现方案.md`.
- **策略优选**: route `/page/strategy/qa/strategy-selection`, sidebar 「问答管理 → 策略优选」. The standalone `src/strategy-selection/` workbench has two horizontal split stages: Step 1 keeps intent-understanding conversation cards on the left and an editable task draft plus angle selection on the right; Step 2 keeps multiplexed parallel strategy cards and automatic judging on the left while the right stays dedicated to the selected-strategy basket and final Markdown synthesis. It consumes the existing `POST /api/parallel-agents/run/stream` protocol, isolates output by stable agent id, supports expanded per-agent dialogs, user selection, Markdown editing/copy/download, and shared server-side DOCX export. A clearly marked neutral Taiwan-Strait risk-management demo is loaded by default for offline UI acceptance. Administrators can edit the SOUL and skills of the nine built-in functional agents through the page dialog; the backend seeds `strategy-selection-{intent,angle-*,judge,solution}` only when their directories are missing, preserving later admin changes. Pure parsing/SSE tests live in `src/strategy-selection/lib.test.ts`; backend seed tests live in `tests/test_strategy_selection_seed.py`.
- **轻应用中心 (Light App Center)**: a sibling of 任务管理 in the sidebar with two pages — 应用管理 (admin registers `window_open` or `iframe` mini-apps with a route-param builder: login params resolved from `localStorage.userInfo`, theme params literal) and 应用列表 (card grid of `window_open` apps, `window.open` launch). `iframe` apps are mounted under a chosen parent menu (XK/PG/TY/综合管理) and **dynamically injected into the sidebar** by `core/page-layout/use-sidebar-menu.ts` (`useSidebarMenuItems`), opening in the `LightAppIframeView` host. Client + React Query hooks in `strategy-components/api/light-apps.ts`; URL builder/constants in `strategy-components/lib/light-app.ts`. Backend: `/api/light-apps` (global/shared, admin-gated writes).
- **菜单管理 (Menu Management, admin-only)**: an **overlay** over the static sidebar menu — `MenuManagementPage` (`pages/MenuManagementPage.tsx`, route `/page/strategy/admin/menu-management`, opened from the admin-only 「菜单管理」 item in the **bottom-left settings dropdown** of `components/page-sidebar.tsx`). Admins rename / 停用·启用 / reorder (↑↓ or @dnd-kit drag) / re-parent (horizontal drag **or** the edit dialog's 「移动到」parent selector) any node across 一级/二级/三级, **including injected iframe light-app nodes** (`light-app-<appId>`). The static tree (`core/page-layout/sidebar-menu.ts`) stays the source of icons/routes; only per-node deltas (`label`/`disabled`/`parentId`/`sortOrder`) persist to the backend. Merge logic in `core/page-layout/menu-overrides.ts` (`applyMenuOverrides`, applied in `use-sidebar-menu.ts` after light-app injection, before role filter; disabling a node hides its whole subtree) — strict **3-level cap** (`wouldExceedDepth`). Client `strategy-components/api/menu-overrides.ts`. Backend: `/api/menu-overrides` (global/shared; open read, admin atomic replace-all). **简介模式** left-nav is a separate overlay: `/api/compact-menu-overrides` stores two independent sets (type `A` / `B`); each website picks one via `runtime-config.js` `VITE_COMPACT_MENU_TYPE`.
- **白名单管理 (Login Whitelist, admin-only)**: gates **who may log in**, run as a **blocklist (黑名单模式)**. Two pieces: a global master switch (`system_settings.json → login_whitelist.enabled`, surfaced by **admin-only** `GET|PUT /api/system-settings/login-whitelist`) + a per-user **放行** flag (`users.approved` column, migration `20260625_02`). Users **self-register** as usual and **every new account defaults to `approved=True`** — so a user who has never logged into this system before is allowed straight through; the switch only blocks users an admin has explicitly **取消放行** (`approved=False`). (`create_user`/`User`/`UserRow` all default `approved=True`; admins are always approved; existing rows are backfilled `True`.) Login interception is the single helper `enforce_user_approved(user)` in `app/gateway/routers/auth.py`, called in all three login endpoints (`/login/{local,username,token}`) **after** the account is resolved/created and **before** the JWT is issued: switch off → everyone passes; `system_role=="admin"` → always passes (anti-lockout); else `approved=False` (admin-revoked) → 403 `{code:"PENDING_APPROVAL"}` (the frontend's `extractErrorMessage` surfaces the message and login throws before writing any auth state, so no half-login). Admin approves on `pages/LoginWhitelistPage.tsx` (route `/page/strategy/admin/login-whitelist`, entry「白名单管理」in the bottom-left settings dropdown of `components/page-sidebar.tsx`, both sidebar modes): a top master-switch + a list of all registered users (`GET /api/v1/auth/users`, now carrying `approved`) with a per-row 放行 Switch (`PUT /api/v1/auth/users/{id}/approval`, admin-only; revoking only blocks the **next** login — `token_version` is left untouched, existing sessions are not force-killed). Client/hooks: switch in `strategy-components/api/login-whitelist.ts`, user list + approval in `core/auth/{api,hooks}.ts` (`useSetUserApproval`). Backend tests: `tests/test_login_approval.py`. **账号级登录口令与密码**已统一,个人口令优先于系统共享口令;新密码保存哈希,旧明文口令兼容校验。管理员重置使用 `PUT /api/v1/auth/users/{id}/login-password`(别名 `/reset-password`),同时更新两种历史凭据字段并撤销旧会话,不再支持清空密码或读取新密码明文。未设置个人密码时使用配置共享口令(默认 `123ewq`);登录开关关闭时保留旧入口兼容行为,开启后禁止免密进入。详见上方「账号登录、自主注册与单点登录」。
- **白名单管理 (Login Whitelist, admin-only)**: gates **who may log in**, run as a **blocklist (黑名单模式)**. Two pieces: a global master switch (`system_settings.json → login_whitelist.enabled`, surfaced by **admin-only** `GET|PUT /api/system-settings/login-whitelist`) + a per-user **放行** flag (`users.approved` column, migration `20260625_02`). Users **self-register** as usual and **every new account defaults to `approved=True`** — so a user who has never logged into this system before is allowed straight through; the switch only blocks users an admin has explicitly **取消放行** (`approved=False`). (`create_user`/`User`/`UserRow` all default `approved=True`; admins are always approved; existing rows are backfilled `True`.) Login interception is the single helper `enforce_user_approved(user)` in `app/gateway/routers/auth.py`, called in all three login endpoints (`/login/{local,username,token}`) **after** the account is resolved/created and **before** the JWT is issued: switch off → everyone passes; `system_role=="admin"` → always passes (anti-lockout); else `approved=False` (admin-revoked) → 403 `{code:"PENDING_APPROVAL"}` (the frontend's `extractErrorMessage` surfaces the message and login throws before writing any auth state, so no half-login). Admin approves on `pages/LoginWhitelistPage.tsx` (route `/page/strategy/admin/login-whitelist`, entry「白名单管理」in the bottom-left settings dropdown of `components/page-sidebar.tsx`, both sidebar modes): a top master-switch + a list of all registered users (`GET /api/v1/auth/users`, now carrying `approved`) with a per-row 放行 Switch (`PUT /api/v1/auth/users/{id}/approval`, admin-only; revoking only blocks the **next** login — `token_version` is left untouched, existing sessions are not force-killed). Client/hooks: switch in `strategy-components/api/login-whitelist.ts`, user list + approval in `core/auth/{api,hooks}.ts` (`useSetUserApproval`). Backend tests: `tests/test_login_approval.py`. **账号级「登录口令」(per-account password — 临时开通)**: the same page also lets an admin assign one specific account an individual **plaintext** password (`users.login_password` column, migration `20260625_04`, nullable; auto-added on startup by `_ensure_orm_columns_sync`). Once set, **that account's** username login (`POST /api/v1/auth/login/username`) **requires** `?password=` to exactly match it and that personal password **takes precedence over** the global shared-password gate (`username_login.require_password`); accounts without one keep today's shared-gate / passwordless behavior. The user then logs in via the **existing** frontend URL `#/login/<用户名>?password=xxxx` (LoginPage already forwards `?password=`; `<用户名>` = the account's email `@`-prefix). **Plaintext is intentional** — the password rides in the URL query anyway, so storing it readably lets the admin re-copy the full login link from the page; it is exposed only on the **admin-only** `GET /api/v1/auth/users` (`UserListItem.login_password`) and the new admin-only `PUT /api/v1/auth/users/{id}/login-password` (set non-empty / clear with null·empty; doesn't touch `token_version`). The whitelist page renders a per-user 「登录口令」 column with a set/修改 editor + a live 「复制登录链接」 button (`useSetUserLoginPassword` in `core/auth/hooks.ts`, `setUserLoginPassword` in `core/auth/api.ts`). Backend gate helper `_lookup_user_by_username` (lookup-only, no auto-register) in `routers/auth.py`; tests `tests/test_login_personal_password.py`.
- **敏感词管理 (Sensitive Word Management)**: configures the **展示层脱敏映射** (原始词 → 替换词). **Gated on the username `lqq`** (not the admin role) — `getAccountDisplayName().toLowerCase() === "lqq"` (username = email `@` prefix, else `user_id`, same as the profile page); the dropdown entry, the route guard, and the page-level guard all use this check. `src/lib/desensitize.ts` ships a frozen seed map `SEED_DESENSITIZE_MAP` (the deployment seed) plus a live mutable `DESENSITIZE_MAP` (initialized from the seed so `desensitize()` works before any fetch). `DesensitizeWordsLoader` (mounted in `App.tsx` `AppProviders`) fetches `/api/sensitive-words` on startup and, if non-empty, calls `replaceDesensitizeMap(...)` to make the backend config the source of truth (empty/failed → keep seed). Page `SensitiveWordsPage.tsx` (route `/page/strategy/admin/sensitive-words`, opened from the 「敏感词管理」 item in the **bottom-left settings dropdown** of `components/page-sidebar.tsx`, present in **both** full + collapsed sidebar modes) lists/adds/edits/启停/deletes words and saves the **whole set atomically** (replace-all); a 「导入种子词」 button merges any missing `SEED_DESENSITIZE_MAP` entries into the editor. Client + hooks in `strategy-components/api/sensitive-words.ts` (`wordsToMap` folds enabled rows into the runtime map). Backend: `/api/sensitive-words` (global/shared; open read, write allowed for admin **or** the `lqq` account), mirroring 菜单管理's store shape. **侧边栏 + 导航栏 menu labels are desensitized** at the data source: `useSidebarMenuItems`/`useActiveThirdLevel` (`core/page-layout/use-sidebar-menu.ts`) map every node's `label` through a desensitizer built **directly from the `/api/sensitive-words` query** (`makeDesensitizer(wordsToMap(words))`, falling back to the global seed `desensitize` while empty) — this sidesteps the `replaceDesensitizeMap` effect-timing race. Only `label` is rewritten; `path`/`id`/`icon` are untouched so routing/highlight are unaffected. All nav surfaces (`page-sidebar.tsx`, `page-sidebar-dark.tsx`, `page-sidebar-v1.tsx`, `strategy-components/Header.tsx`, `PageRoutes.tsx`) consume this hook and are covered; `MenuManagementPage` uses the raw tree so admins still edit real labels.
- **技能地址管理 (Skill Address Management, admin-only)**: 扫描运行中的技能(`skills/{public,custom}` 下所有 `.md`/`.py`)里的 **http(s) URL 与 IP/IP:端口**,按唯一地址聚合全部出现位置(跨 .md/.py),支持**批量替换**(如把 UAT 地址一次性改成生产)。主体抽成可复用组件 `SkillAddressesPanel`(`pages/SkillAddressesPage.tsx` 导出,默认导出 `SkillAddressesPage` 仍保留旧路由 `/page/strategy/admin/skill-addresses` 作直链回退),**作为「技能地址管理」标签页嵌入管理员「技能管理」页 `pages/AdminSkillsPage.tsx`**(该页加 Tabs:「技能列表」+「技能地址管理」;入口在「设置和更多」下拉的「技能管理」`workspace-nav-menu.tsx` → `/page/workspace/admin/skills`,不再单列于 `components/page-sidebar.tsx` 左下角设置下拉):打开自动扫描并带**进度条**(扫描逐技能 / 应用逐文件 X/N,应对 150+ 技能),URL/IP 类型过滤 + 搜索 + 「片段批量套用」(如所有 `uat.4.cn` → `prod.4.cn`)、每地址「替换为」输入框(可展开看 `file:line` 片段)、内联**预览**、**应用**、**多关键词检索**(空格分隔全部命中),以及**修改记录**面板——每次应用生成一条记录(显示时间/改了哪些地址 from→to/文件数/处数),可**针对单次记录回退**(二次确认)。client + NDJSON 流式解析在 `strategy-components/api/skill-addresses.ts`。后端 `/api/skill-addresses`(**仅管理员**):所有文件 IO 走 `asyncio.to_thread` 不阻塞事件循环;`GET /scan`(+`/scan/stream`)、`POST /preview`、`POST /apply`(+`/apply/stream`)、`GET /backups`、`POST /rollback/{id}`;**子串安全替换**(基于 token span,不会误伤子串)、`expected_total` 乐观锁(409)、写前自动磁盘备份到 `{skills_root}/.address-edits/`(同时写一份 `{id}.manifest.json` 记录本次替换明细,供修改记录展示)、应用后刷新技能系统提示缓存。纯引擎 `deerflow/skills/address_scan.py`,router `app/gateway/routers/skill_addresses.py`,tests `tests/test_skill_addresses.py`。范围仅运行中技能,不动 `deploy/minimal/skills/`。
- **按钮管理 (Task Button Management, admin-only)**: configures the **可配置跳转按钮** rendered in the left task panel of the task deep-link workspaces (rwfx / 3qfx / xdfx, see `TaskFxWorkspace`). Each button = `{business, label, linkType, target, appendTaskId, idParam, idKind, openMode, loginParams, appendAuth, authTokenParam, authNameParam, enabled, sortOrder}`; `linkType` is `url` (外链 `window.open`, optional append of `?{idParam}={id}` — **`idParam` is the editable query-param name**, e.g. `id`/`task_id`), `business` (内部切换到另一业务, reuses `resolveTaskDeeplinkTarget`, always task id), or `purpose` (弹出当前任务的「任务目的」表格 via the shared `TaskPurposeDialog`, no target — configurable for any page incl. xdfx). **`host`(宿主路由)** asks the embedding parent to navigate: `runTaskButton` sends `window.parent.postMessage({ type:'HOST_NAVIGATE', path, queryParams:{ [idParam]: Number(taskId) } }, hostOrigin)` — `target` is the host route (e.g. `/task/item-aiceh/step-analysis-audience`), `appendTaskId`/`idParam` become numeric `queryParams` (task id only), origin from `runtime-config.js` `VITE_HOST_NAVIGATE_ORIGIN` (else ancestorOrigins/referrer; never `*`). Independent-tab clicks toast and do nothing. **`url` buttons support two independent, coexisting login-append mechanisms**: (1) **`loginParams` (追加登录参数, like 应用管理/Light App Center)** — a list of `{key, source, customValue}` resolved at click time: `runTaskButton` reads `userInfo` (via `readUserInfo` from `strategy-components/lib/light-app`, embed-isolated through `authStorage`) and appends `?{key}={value}` for each (`source` = a userInfo field such as `accessToken`/`yUserId`, or `other` → literal `customValue`); empty list = nothing appended. Reuses `LOGIN_SOURCE_OPTIONS` from light-app; stored as JSON column `task_buttons.login_params_json` (`PortableJSON`, migration `20260625_01`). (2) **`appendAuth` (追加登录态)** — appends `?{authTokenParam}={token1}&{authNameParam}={username}` (default param names `token`/`username`) so the跳转目标外部系统 can identify the current user — e.g. `…/action/sentiment?token=<JWT>&username=lizhaoxing`. **Gated on token login**: `token1` = the `?authToken=` used by token-exchange login; `username` = the raw login name the backend resolved from `getTokenInfo`. Both are stashed at login by `persistLoginCredentials` into `login.token1`/`login.username` (`core/auth/login-credentials.ts`, scoped via [[scoped-storage]] so嵌入/独立会话隔离 + 随独立会话迁移). Only token login writes them → a non-token-login session has no `token1`, so `runTaskButton` silently skips the auth append (the jump still works, just without those two params). The frontend reads `username` straight from the new `UsernameLoginResponse.username` field (the stored email local-part is lossy — lowercased/normalized — so not used), **not** by decoding the JWT. Stored as columns `task_buttons.{append_auth, auth_token_param, auth_name_param}` (migration `20260625_02`). The admin page renders both editors for `url` buttons (loginParams 虚线框 + 追加登录态 switch). **`idKind` (`task`/`action`) only matters for xdfx**: its deep-link `?taskId=` is an 行动id and the 任务id is resolved at login (`fetchTaskIdFromAction`) — `TaskContext` now also stashes the raw `actionId`, so a url button can append either (default `task`). Page `TaskButtonsPage.tsx` (route `/page/strategy/admin/task-buttons`, **admin-gated**, entry「按钮管理」in the bottom-left settings dropdown of `components/page-sidebar.tsx`, both full + collapsed modes) has per-business tabs, edits name/type/target/启停/排序/增删, saves the **whole set atomically** (replace-all), plus 「导入默认」 to merge code-seed defaults. **Seed/fallback** (like 敏感词管理): only when the whole table is empty (fresh deploy, never saved) do the workspace + page fall back to `defaultTaskButtons(cfg)` — rwfx's url buttons (编辑/上一步/下一步/3q详情) built from the **live** `/api/public/config/task-deeplink` plus cross-business switch buttons for **all three** businesses (each switches to the other two — rwfx→三情/行动, 3qfx→任务/行动, xdfx→任务/三情). Once saved, the store is the sole source of truth. **Bottom 快捷跳转 bar groups by prev/next**: `TaskJumpBar` renders only「上一步/下一步」-type buttons in the bottom bar — a `prev` group (id 含 `prev` 或文案「上一步」, 描边次要样式 + ←图标) rendered **左侧**, then a `next` group (id 含 `next` 或文案「下一步」, 实心主色) on the **右侧** (container `justify-end`); everything else goes to the right-edge floating menu. The default 上一步 button (`rwfx-prev`, `url`, target = `DASHBOARD_AGENT_ROUTE` `/page/strategy/dashboard-agent`, `appendTaskId` + `idParam=taskId` → `?taskId=任务id`, `openMode=self`) 默认指向**应用内**「大屏绘制」Line truncated
- **实时并发监控 (Concurrency / System-Pressure Monitor, admin-only)**: a live panel mounted at the **top of the admin 排行榜 page** (`components/workspace/admin/concurrency-monitor.tsx` `ConcurrencyMonitorPanel`, rendered in `pages/AdminUserLeaderboardPage.tsx`) showing **当前并发的大模型调用数 + 列表(用户/智能体/类型/已运行时长)**, each row with a 「停止」button (and a 「全部停止」) that **truly aborts** that run's in-flight model stream via `RunManager.cancel` (`POST /api/admin/active-runs/{run_id}/cancel`) — to relieve pressure when 使用人数过多. Two line charts (minute/hour toggle): **并发量折线图** (peak/avg, `GET /api/admin/active-runs/concurrency`, fed by a lightweight background sampler into `concurrency_samples`) and **大模型出字速度折线图** (tokens/sec, `GET /api/admin/active-runs/token-speed`, aggregated from `llm_call_metrics`) so a dip pinpoints where the bottleneck is. A **「后台采样」Switch** (`system_settings.json → concurrency_monitor.enabled`, **default off / opt-in**, `GET|PUT /api/admin/active-runs/settings`) turns the background sampling on/off **at runtime, no restart** (the live concurrency count + 「停止」 work even while sampling is off — only the 并发量 history chart needs it on); everything is designed to **never impact production** (one tiny INSERT/15s, retention-purged, best-effort). Client/hooks: `core/admin/active-runs.ts` + `core/admin/hooks.ts` (`useActiveRuns`/`useConcurrencySeries`/`useTokenSpeedSeries`/`useCancel*`/`useMonitorSettings`). See the backend CLAUDE.md「Admin Concurrency Monitor」.
- **会话冲突与模型工具流恢复**: when a user submits a new question while the previous turn is still streaming, the backend's `RunManager.create_or_reject` rejects with HTTP 409 (`services.py` returns the Chinese detail「当前对话还在生成回答…」). `core/threads/hooks.ts` detects the conflict and routes it through `confirmOrRejoin`. Run-creation SSE responses expose `Content-Location` plus the SDK `Location` reconnect endpoint; `core/api/api-client.ts` records the last consumed event id, so an in-page rejoin resumes after that cursor instead of replaying tool arguments from `-1`. `write_file` argument updates carried by `messages-tuple` count as business activity. A known active run is probed only after 90 seconds without a business frame; the watchdog hides `lg:stream`, stops only the old browser reader, and rejoins without cancelling the backend run. Clean EOF, transport errors, 409 and watchdog recovery share one single-flight Promise to prevent duplicate joins/finalization. The backend `PatchedChatOpenAI` separately normalizes confirmed cumulative argument snapshots and bounded compatible response shapes while preserving standard deltas; its content-free diagnostics never log prompts, arguments or file bodies.
- **React #185 与流式刷新保护**: every direct LangGraph `useStream` surface (main/agent chat, AI writing, Canvas and Studio notebook) uses shared `STREAM_RENDER_BATCHING = true`. The installed SDK implements numeric `throttle: 16` as a trailing debounce, which can indefinitely postpone UI updates during a continuous fast stream; `true` retains asynchronous next-task batching without requiring 16ms silence. `stream-error-classification.ts` detects `Maximum update depth exceeded` / production `#185` through bounded, cycle-safe wrappers. Main chat filters the SDK's stored error and duplicate submit rejection; `react-ui-error.ts` gives each send at most one automatic UI recovery, then pauses rejoin without cancelling the server run. Token activity must not reset that budget. The top-level `ReactUiErrorBoundary` catches only this render/commit error, shows a static friendly reload panel, and never automatically remounts the failing tree. Other errors are not swallowed. Shared toasts are deduplicated for 30 seconds; diagnostics retain error type, recovery phase, thread/run identifiers and component stack but never message/tool content. Real SDK SSE replay covers partial reasoning and write_file Markdown before generation ends; the browser boundary check triggers a real production React layout-effect loop and requires manual reload to recover. These safeguards do not prove the unknown production component loop is fixed.
- **流式游标作用域**: resumable cursors belong to the current SDK message accumulator, not a module-global map. `createStreamAPIClient` isolates same-reader recovery; newly mounted chats and real thread switches must replay the retained prefix instead of borrowing another reader's consumed position. Clearing replaces the cursor map so late old-reader events cannot pollute the new scope. The shared `getAPIClient` does not rewrite replay-from-start cursors. `stream-cursor-replay.test.ts` uses the real SDK to protect against both duplicate tool arguments on reconnect and missing prefixes on reopening.
- **单智能体任务深链聊天记录(2026-10-19)**: `3qfx` / `rwfx` / `xdfx` 已不再通过 `useTaskThreads` 扫描、过滤通用 `threads_meta` 列表;`TaskFxWorkspace` / `TaskFxIndexResolver` 统一调用 `useTaskDeeplinkThreads` → `GET /api/task-deeplink-threads?task_id=&go_path=`,读取独立表 `task_deeplink_threads` 的 `(task_id, go_path)` 索引,再按 `thread_id` 关联 canonical `threads_meta` 标题/状态(消息与 checkpoint 仍由 LangGraph 管理)。新会话 metadata 写 `taskRecordId`、`taskGoPath`、`thread_type=task_deeplink` 并由 thread-meta 仓储同事务登记;`3qfx/rwfx` 的 `taskRecordId` 是任务 id,`xdfx` 是 URL 原始行动 id(真实任务 id 仍保留在 `metadata.taskId` 维持共享访问语义)。普通聊天记录默认隐藏该 thread type;显式 taskId 查询仍可读取。迁移 `20261019_01` **只建表、不回填旧数据**,因此上线前旧深链会话不会出现在新列表。`/api/open/3qfx/ask` 同样写专用索引。Tests: `packages/harness/tests/test_task_deeplink_threads.py`, `src/core/auth/task-purpose-metadata.test.ts`, `src/core/threads/hidden-chats.test.ts`。
- **会话冲突 409 中文化**: when a user submits a new question while the previous turn is still streaming, the backend's `RunManager.create_or_reject` rejects with HTTP 409 (`services.py` now returns a **Chinese** detail「当前对话还在生成回答…」). `core/threads/hooks.ts` `onError` detects the conflict (`isActiveRunConflictError`: 409 / "already has an active run" / the Chinese text). A premature SSE close (SDK treats it as success and restores the send button while the backend run is still occupying the thread) is recovered by `confirmOrRejoin`: hold the stop button, `joinStream` the live run, and on 409 auto-reconnect instead of a fake AI bubble. `sse_consumer` no longer ends a resumable (`on_disconnect=continue`) stream on a false-positive `is_disconnected()`.
- **State**: TanStack Query for server state, context providers (`SubtasksProvider`, `ArtifactsProvider`, `PromptInputProvider`) scoped to `WorkspaceRoutes`
- **LLM streaming**: `@langchain/langgraph-sdk` streams messages from the backend via SSE
- **UI**: Radix UI primitives + TailwindCSS v4 + shadcn-style components in `src/components/ui/`
@@ -144,10 +104,6 @@ The frontend (`frontend-web/`) is a React 19 + Vite SPA:
### Configuration
普通问答与智能体问答的 `write_file` 流式展示:`namedStreamingWriteFilePath` 统一判断路径是否可用;缺少路径、路径尚未完整或只有占位名时,不生成虚拟文件来自动打开沙箱,而由 `message-group.tsx` 在步骤内用绿色小字展示正文。步骤参数合并 `tool_calls` 与 `tool_call_chunks`,后续收到真实路径时复用原工具调用 ID 恢复正常文件预览;`outputs` 下真实文件的自动打开和沙箱流式预览保持原流程。
沙箱文件正在生成时,ArtifactsProvider 的 `select` / `openStreamedArtifact` 阻止切到其他文件;手动操作提示「当前文件正在生成,请稍等片刻,完成后就可以切换查看其他文件。」,自动选择静默跳过。ChatBox 按选中文件的未完成 write_file 和运行状态注册锁,预览组件同时覆盖流式写入及全文改写;完成、停止或卸载时移除所属锁。同一个文件的虚拟预览和真实路径视为同一目标。
Backend config lives in `offline-backend-20260512/backend/config.yaml`. Values starting with `$` resolve as environment variables (e.g., `$OPENAI_API_KEY`). MCP servers and skills are configured in `extensions_config.json` in the same directory.
## Detailed Backend Reference
@@ -1,188 +0,0 @@
# 报告协作工作台 — 交互重设计方案(v2)
> 日期:2026-09-07
> 状态:**待确认**(确认后按 §7 分期实施)
> 取代:现行「规则澄清 + 三张模板方案卡 + 画布为主」的交互
> 原则:回到最初设计 —— **协调者智能体全程与用户对话的主线**
---
## 1. 设计目标与总体形态
用户视角只有一条主线:**和一个规划师智能体对话 → 它摸清意图并规划工作流 → 确认后执行、过程在流程图上可见 → 随时插话干预、指定智能体重跑 → 最终成稿、继续对话式修改**。
```
┌─────────────────────────────────────────────────────────┐
│ 阶段1 计划模式 阶段2/3 执行+干预 阶段4 成稿 │
│ ┌───────────┐ ┌───────────┐ ┌──────────┐ │
│ │ 规划师对话 │ 确认 │ 聊天时间线 │ 审稿过 │ 对话改稿 │ │
│ │ 需求摘要卡 │ ─────→ │ +成员Tab │ ─────→ │ 版本/diff│ │
│ │ 工作流卡 │ 冻结 │ +流程图动画│ 报告卡 │ 上游重跑 │ │
│ └───────────┘ └───────────┘ └──────────┘ │
│ ↑ 回到计划模式(replan)随时可触发 ↑ │
└─────────────────────────────────────────────────────────┘
```
与现行的核心差异:
| 维度 | 现行(做偏的) | v2 |
|------|----------------|-----|
| 需求澄清 | 规则模板问句秒回 | 规划师智能体(LLM)领域化提问 |
| 工作流来源 | 3 张确定性模板 | LLM 按意图生成自定义 DAG,对话迭代修改 |
| 执行展示 | 画布为主、聊天为辅 | **聊天时间线为主**(成员 Tab 切换保留),**执行状态在流程图上动画呈现** |
| 干预 | 命令确认卡体系 | 输入框常开 → 协调者智能体分类;支持**指定智能体重跑** |
| 报告修改 | 改写候选(纯文字层) | 意图分流:润色走改写;**事实性问题触发上游节点重跑** |
---
## 2. 阶段 1:计划模式 — 需求梳理与工作流规划
### 2.1 计划模式状态
- 用户发出第一条需求消息起进入**计划模式**,Header 显示徽章「📋 计划模式」,输入框提示语切换为「梳理需求中,你可以随时补充或纠正…」。
- 计划模式在**工作流确认冻结**时结束;执行期大改可通过 replan 回到计划模式(见 §5.4)。
### 2.2 规划师对话(LLM,替换现行规则路由)
- 必须调用独立内置智能体 `report-collaboration-intent` 的真实 LangGraph thread,并原样消费 `messages-tuple` SSE;禁止用 `ainvoke()` 等待完整 JSON 后再包装成一话。
- 流式正文、思考内容和工具步骤直接进入工作台现有 `MessageList`,与普通智能体问答采用同一套步骤条 / Reasoning 展示。
- 模型:`report_collaboration.planner_model`(回退 `coordinator_model` → 默认模型,复用现有 model_resolver 冻结机制)。
- 提问是领域化的:写市场分析就问「关注整车还是供应链 / 要不要竞品对比 / 给谁看 / 篇幅」,而非固定模板问句。
- 澄清轮次上限沿用 `max_clarification_rounds`;用户随时可以说「直接开始」按默认假设推进。
### 2.3 需求摘要卡
信息足够后,规划师在对话中输出一张**结构化需求摘要卡**(业务卡插槽渲染):主题 / 目的 / 读者 / 角度清单 / 篇幅与重点 / 默认假设。用户逐项看,可在对话里继续改(「读者改成投资人」→ 卡片更新出新版)。
### 2.4 工作流生成与迭代
- 规划师判断意图信息足够后,立即按已确认意图自动生成**一份**工作流方案(不是三选一),不再要求用户额外点击“确认意图/生成方案”;方案以工作流卡(成员构成、各节点使命、预计时长/成本)+ 右侧流程图预览呈现。
- 生成约束(保证可执行):**节点类型受词表约束** — `research / verify / analyze / write / review`;自由的是结构(几条线、并行还是串行、核验深度)与每个节点的使命/角度/工具。
- 对话式修改:「把价格策略单独拆一条线」「加一个政策风险分析」→ 规划师修订后出新版工作流卡(带变更说明),再确认。
- 「开始执行」→ 冻结需求 + 工作流(含模型/预算快照,沿用现有 freeze 机制)。
---
## 3. 阶段 2:执行 — 过程在流程图上可见
### 3.1 流程图动画规格(执行状态的可视化主载体)
节点状态 → 样式(`ReportFlowCanvas` / `ReportFlowNode`,状态源 `selectNodeStatusMap`,事件源 `node.status.changed` SSE):
| 状态 | 节点样式 | 连入边 |
|------|----------|--------|
| planned / queued | 灰色常态 | 静态 |
| **running** | 主色描边 + **呼吸脉冲动画**(ring)+ 角标 spinner | **流动动画**(@xyflow 内置 `animated: true` 的 dash 流动) |
| **completed** | 绿色 + ✓ 角标,常驻 | 恢复静态实线 |
| failed | 红色 + 错误角标 | 红色虚线 |
| awaiting_input | 橙色 + ?角标 | 橙色静态 |
| interrupted / superseded | 半透明降级 | 灰 |
- 语义:**边流动 = 数据正在流入该节点**(该节点执行中);节点完成即停动画换完成样式。
- 实现成本:@xyflow 原生支持 animated 边与自定义节点 className,纯 CSS 补呼吸动画即可,无需新依赖。
### 3.2 聊天区(保留现有 Tab 切换)
- 并行成员沿用 **AgentStageSelector Tab 切换**(维持现状,不改交错时间线)。
- 每个 Tab 内是该成员的完整流式输出:思考、工具调用卡、检索过程、正文 —— 与普通智能体问答同观感(message-adapter 已具备映射能力)。
- 协调者播报(「研究线 A 完成,核心发现 X,开始交叉核验」)进入总时间线 Tab。
---
## 4. 阶段 3:干预 — 对话即干预 + 指定重跑
### 4.1 输入框常开,协调者智能体分流
执行期输入框永远可用,所有输入先到协调者(LLM 分类,规则高精度直判兜底——复用 RC-BE-014 IntentRouter 骨架,把「规则优先」反转为「LLM 优先 + 规则快路径」):
| 用户意图 | 协调者行为 | 生效时机 |
|----------|-----------|----------|
| 提问(「查到什么了?」) | 直接回答 | 立即,不打断 |
| 修正方向(「重点看下沉市场」) | 小改:在安全点注入 overlay,并回复说明 | 下个安全点 |
| **指定重跑**(见 §4.2) | 出确认卡 → 重开节点 attempt | 确认后 |
| 大改(砍线/加线) | 提议 replan → 回计划模式 | 用户确认 |
| 停止 | 直接取消 | 立即 |
### 4.2 指定智能体重跑(新增核心交互)
**场景**:用户发现某节点传给下游的信息不对(如研究线 B 的结论有误)。
两个入口,同一后端动作:
1. **对话**:「研究线 B 的结果不对,重新查,重点看价格战」→ 协调者解析出 `node_id` + 新指令;
2. **画布**:点节点 → 抽屉(NodeInspectorDrawer)加「↻ 重新执行」按钮。
**级联规则**(复用并补全 ledger 的 targeted rework):
```
重跑节点 N(attempt+1,带用户新指令作为 mission overlay)
→ N 完成 → 所有直接/间接依赖 N 产物的下游节点标记 superseded
→ 按 DAG 依赖序逐波重跑(边动画重新流动,用户全程可见)
→ 受影响章节重新生成
```
- 确认卡必须展示**影响面**:「将级联重跑 核验B / 分析 / 写作 共 3 个节点,预计 +8 分钟」。
- 成本保护:级联重跑计入 run 预算(现有 budget 机制),预算不足时明确报因。
---
## 5. 阶段 4:报告成稿与对话式修改
### 5.1 成稿
审稿通过 → 报告卡出现在时间线(点开 ReportPreviewDialog 全文),协调者播报总结(各线核心发现 → 结论如何形成)。
### 5.2 修改意图分流(协调者 LLM 判定)
| 用户说 | 判定 | 动作 |
|--------|------|------|
| 「把第二章结论写得更笃定」 | 文字润色 | 改写候选(现有 rewrite API)→ 对比预览 → apply → 新版本 |
| 「这个数据不对 / 重新收集一下」 | **事实性问题** | 定位来源节点 → **触发该节点重跑(可带新角度)→ 级联 §4.2 → 受影响章节重生成 → 新版本** |
| 「再从供应链角度补一节」 | 结构性新增 | replan:回计划模式改工作流(只增不删已完成部分) |
| 「恢复到上一版」 | 版本回退 | 现有 restore API |
- 版本链:每次 apply / restore / 级联重跑产出均产生新 head,历史完整保留(现有机制)。
- 修改对话里协调者必须先**复述理解**(「你是想让研究线 B 换个角度重查,然后重写第三章,对吗?」)再执行,避免误触发昂贵的级联。
---
## 6. 工程改造清单
### 6.1 保留(本次联调已验证)
- 持久化 13 张表 + durable SSE + `after_seq` 断线续传;幂等键 / 乐观锁 / 预算框架。
- MessageList 复用链路(message-adapter → LangGraph Message → 业务卡插槽)。
- AgentStageSelector Tab、commands 安全点骨架(RC-BE-014)、报告版本三件套(RC-BE-015)、前端 hooks/reducer/selectors 主体。
- 「清空历史」「生成候选方案」等本次新增入口。
### 6.2 后端重做 / 新建
| 项 | 说明 |
|----|------|
| 规划师智能体 | LLM 多轮澄清(替换 `requirement/intent_router.py` 规则路由)+ 需求摘要结构化 + **工作流 LLM 生成**(受 §2.4 词表约束,替换 `planning/controller.py` 三模板)+ 对话式工作流修订 |
| 协调者智能体升级 | 干预分类 LLM 优先;修改意图分流(§5.2);执行前复述确认 |
| 指定重跑 + 级联 | ledger targeted rework 补全级联 superseded/重跑波次;确认卡带影响面计算 |
| AgentScope 适配器修复 | `count_tokens` 协议缺失(上下文压缩必崩);attempt 耗尽终态化(防僵尸 run) |
| 事件补齐 | 边流动所需的节点状态事件已有;补「级联影响预告」事件 |
### 6.3 前端重做 / 新建
| 项 | 说明 |
|----|------|
| 计划模式 UI | Header 徽章、composer 提示切换、需求摘要卡、工作流卡(替换现三张模板卡) |
| 流程图动画 | running 节点呼吸动画 + 入边 `animated`、completed ✓ 样式、级联重跑时边动画重流(§3.1) |
| 节点抽屉 | 加「重新执行」按钮 → 确认卡 |
| 干预交互 | 执行期输入框常开;意图确认卡(含影响面);修改对话复述确认 |
| 布局 | 聊天为主、画布为辅的默认比例微调(不动整体两栏结构) |
---
## 7. 实施分期
| 期 | 内容 | 验收 |
|----|------|------|
| **P0 地基** | AgentScope `count_tokens` 修复;attempt 耗尽终态化;级联重跑的 ledger 补全 | 执行阶段不崩、无僵尸 run、单节点重跑级联正确(后端测试) |
| **P1 计划模式 + 执行可视化** | 规划师 LLM 对话、需求摘要卡、工作流 LLM 生成与迭代、计划模式 UI、流程图动画 | 从新会话到确认工作流全程对话完成;执行时动画正确随状态流转 |
| **P2 干预 + 成稿修改** | 协调者 LLM 分类、指定重跑(两入口 + 影响面确认卡)、报告修改意图分流、上游级联重跑 | 四类干预各自走通;「数据不对→重跑→新章节→新版本」全链路 |
每期结束跑 RC 全量测试(当前基线 233 通过)+ 前端 26 单测,不引入对其他模块的影响。
@@ -229,27 +229,23 @@ sequenceDiagram
```http
POST /api/report-collaboration/sessions
POST /api/intent/init
POST /api/intent/stream
POST /api/report-collaboration/sessions/{sessionId}/intent-turns
POST /api/report-collaboration/sessions/{sessionId}/messages
Content-Type: application/json
{ "text": "请写一份…", "target_node_id": null, "agent_run_id": null }
```
- 报告页面固定调用内置 `report-collaboration-intent` 智能体;`/api/intent/stream` 原样透传 LangGraph `messages-tuple`,不是等待模型完成后包装响应。
- 正文 token、provider reasoning 和工具调用步骤实时写入当前 `MessageList` 气泡;终态后 `/intent-turns` 只负责持久化镜像与状态交接,不再调用模型识别意图。
- 旧 `/sessions/{sessionId}/messages` 在 `empty/clarifying` 阶段返回 `409 USE_STREAMING_INTENT`,防止退回阻塞式 `ainvoke` 路径。
- `useReportCollaborationSession.send()`:当 `session.status` 不是 `running` / `awaiting_input` / `reviewing` 时走 `sendMessage`。
- 会话状态:`empty` → `clarifying` → `planning` → `proposal_ready`。
- 澄清问题以 `CollaborationMessage` 进入时间线;业务卡通过 `MessageList` 的 `businessCardSlot` 渲染(`additional_kwargs.report_collaboration_card`)。
- 意图智能体输出 `INTENT_READY` 后,`POST /intent-turns` 自动创建并完成 `plan_request`;前端无需再展示“确认意图”或“生成候选方案”按钮。
### 5.3 阶段 2:候选方案
```http
# 正常路径:由最后一轮 POST /messages 自动触发规划
POST /api/report-collaboration/sessions/{sessionId}/plan-requests
POST /api/report-collaboration/sessions/{sessionId}/plans/{planId}/select
```
- `POST /plan-requests` 仅保留给“重新生成”与兼容调用,不是首次规划的必经步骤。
- 规划师尚未判定 `ready` 时直接调用该兼容接口会返回 `422 REQUIREMENT_NOT_READY`,防止跳过意图确认。
- **预览方案**(`previewPlanId`):纯前端,不调 API。
- **采用方案**:`select` 写 `selected_plan_id`,**不**创建 run。
- 409:方案 revision 过期 → 前端 `refreshSnapshot`,提示用户重选。
@@ -1,105 +0,0 @@
# 本地问答、资料库与技能并发验收
测试日期:2026-09-28 至 2026-09-29 凌晨。环境:Windows、约 8GB 物理内存、Python 3.12、Node 22、Gateway 单进程、SQLite、默认 MiniMax-M2.5。前端 Vite 5174,Gateway 8001。模型并发限流与 Redis 分布式门控未启用。
本次保留并验收了工作区原有的资料库索引、问答收尾、沙箱超时和流式恢复修改,另外修复了压测复现的技能刷新重复校验,以及真实地图问答暴露的内部待办提醒显示问题。测试结果不能等同于 Linux 多进程生产环境容量。
## 版本范围
开始测试时本地为 `3a07c476`,没有 `cognitive-situation-map`。随后拉取远程,发现 `origin/master` 已前进至 `3107f2cc`,包含该技能的初始化及 v2.6.0 精简运行时。保留本地修改后合入远程,合并提交为 `c9effe83`;最终绘图与多用户测试以合入后的代码为准。
旧本地版本里 `page-report-generation` 的地图仅支持中、美、日、台,因此其“不支持菲律宾”的反馈不能用于评价最新的 `cognitive-situation-map`。
## 真实问答
使用独立普通测试账户,阶梯间顺序运行,逐条检查预期测试关键词与结果、SSE `end`、持久化 `success`,结束后删除本轮生成的测试线程。1/3/5/10 路检查正文包含“测试”和数字 4;20 路增强为检查“测试正常”及明确的“2加2等于4”。这属于简单问答验收,不是复杂内容质量评测。
| 同时问答用户数 | 成功 | 首段答案中位耗时 | 流结束中位耗时 | 流结束最慢 |
|---|---:|---:|---:|---:|
| 1 | 1/1 | 5.792s | 6.439s | 6.439s |
| 3 | 3/3 | 2.214s | 3.245s | 3.287s |
| 5 | 5/5 | 2.885s | 3.702s | 4.373s |
| 10 | 10/10 | 2.920s | 4.796s | 5.416s |
| 20 | 20/20 | 4.364s | 10.622s | 11.135s |
累计 39/39 通过。20 用户整批耗时 11.829s,同期 health 12/12 成功、中位 13ms、最大 371ms。这里是一次阶梯短时突发,并未证明百用户持续长任务容量。
取消接口返回 204,58ms 后状态为 `interrupted`,测试线程删除返回 200。同期健康探测 20 次均成功,中位 9ms,最大 3.044s;说明仍存在数秒调度尖峰,不能仅凭平均值宣布无阻塞。
早期多个磁盘基准同时运行时,单路首段答案为 33.853s,日志显示同步 agent 构建 28.344s,health 也有 5s 超时。这批明确有本机资源争用,不纳入稳定容量结论。开发脚本启动的服务进程还曾消失,没有拿到退出或 reload 日志,原因未确认;期间的连接失败剔除。后续使用无热重载的固定进程复测。
## 资料库和知识库
- 资料库/知识库相关回归 186 项通过;资料库新存储 Memory/SQLite 专项另有 8 项通过,覆盖用户隔离、分页、原子换代、并发租约和旧任务围栏。
- 真实测试账户看到 2 个共享知识库;选中的库包含 668 份文档、168 个 Wiki 页面。首次 hybrid 查询 3.58s,返回 5 条。
- 排除合成磁盘负载后,空资料库、知识库目录和 hybrid 查询分别测试 1/4/8 并发,每档 8 次,总计 72/72 HTTP 200,零异常。
| 接口 | 8 并发中位耗时 | 8 并发最大耗时 |
|---|---:|---:|
| 资料库列表(空测试账户) | 165ms | 224ms |
| 知识库目录 | 517ms | 557ms |
| hybrid 检索(相同问题、5条结果) | 426ms | 441ms |
这组重复使用同账号和查询,包含热缓存效果;空账户列表不代表有大量文件的资料库。独立测试 SQLite 另生成了 101 个合成用户、10 万条资料元数据,480 次查询全部成功;其中单用户 5 万条资料关键词查询 P95 为 1.08s、首页 P95 为 130ms,但此轮同时有其他 IO 测试,只作为规模观察值。
资料库索引按 5 分钟过期刷新;进程异常退出时正在同步的租约最多等待 30 分钟恢复。大库关键词查询仍使用多字段包含匹配,不能据当前测试证明生产规模检索始终快速。
## 大技能与并发刷新
文件体积大和小文件数量多分别测试,使用隔离临时目录,不改真实技能内容。
| 场景 | 结果 |
|---|---|
| 真实技能副本,269 文件 / 2.75MiB,稳定缓存 64 并发 | 全成功,约 1.05s;早期混合负载观察值 |
| 同副本改 1 个资产,32 并发,修复前混合负载 | 27 成功、5 个 30s 锁等待超时,复现问题 |
| 独占配对:同副本改 1 个资产,32 并发,旧逻辑 | 32/32 成功,P95 13.700s,最大 14.842s |
| 独占配对:同场景,新逻辑 | 32/32 成功,P95 / 最大 3.963s,P95 降低约 71% |
| 128MiB 资产、34 文件,新逻辑 | 冷初始化 5.54s;变更后 32 并发 P95 0.584s,全成功 |
| 约 160 技能、5120 个小文件(修复前规模观察) | 冷加载执行者约 107s,31/32 等待者超时;热校验约 18s |
修复让同一进程内、相同权限配置的一批重叠请求共享一次刷新及最终校验。等待者仍检查当前缓存身份、权限哈希和能力标记;失败或技能下线时不返回旧视图。新增 8 项回归连同原有 62 项,共 70 项通过。
**剩余风险:** 数千个小文件的单次 Windows 元数据扫描仍昂贵,本次修复没有消除这项成本,也未证明跨进程刷新能合并。不能把 32/64 个技能调用线程等同于 32/64 个真实模型用户。
实际调用 `gongwen-assistant` 读取技能并输出短通知,10.672s 内正常结束,无工具卡住。但答案把要求的 10月8日改成10月15日:通信/技能读取通过,内容日期遵循失败,不能记为整体语义验收通过。
## 绘图与界面
普通问答已实际生成菲律宾地图底图及马尼拉、吕宋北部、巴拉望、棉兰老四个点位,点位弹窗可打开。使用明确标注的虚构数据,未进行时事真实性评估。初次模型额外要求确认消息内地图,回复确认后完成,属于可见的额外交互成本。
这次真实对话发现 `todo_completion_reminder` 被当作用户问题展示。修复后,后端待办提醒带 `hide_from_ui`,前端也按两个历史内部名字过滤聊天和问题导航;真实用户引用 `<system_reminder>` 的文本仍保留。后端 3 项、前端新及关联分组 12 项通过。
最新 `cognitive-situation-map v2.6.0` 已经通过真实问答完整调用:读取技能和菲律宾参考 JSON、写入场景、调用技能自带 `node render.mjs`、检查文件、`present_files` 交付,42.481s 完成,SSE 正常结束并保存 `success`。产物标题为“菲律宾冲突认知态势图(功能验收示意)”,包含 4 个事件、4 个标注、3 个行为体和 2 条连线,明确标注所有事件与等级均为测试数据。输出 `status=ok`、无恢复和警告。模型曾发起两次过宽的目录 glob,被技能访问隔离拒绝后自行改用指定技能目录完成,没有循环卡住。
同一最新技能的直接渲染为 624ms;8 个并发独立渲染进程全部成功,范围 650–949ms。围栏/截断/缺失字段/约 600KiB 场景输入的恢复、非空目录拒绝覆盖、脚本结束标签转义均完成专项检查。真实 Windows LocalSandbox 虚拟路径经 PowerShell 调用 Node 成功(含冷 shell 7.85s)。CSS、JS、菲律宾底图和旗帜资源均返回 200;2.93MB 底图一次请求耗时 208ms。8 个渲染进程不等于 8 个同时生成长内容的模型用户。
**最新 HTML 的视觉验收未通过:** 测试账户能在会话中看到生成文件卡片,文件接口返回 200,源码模式能显示 HTML、正确资源地址和页面结构,但 Codex 内嵌浏览器的预览面板空白;DOM 中 iframe 的 `src` 为 `blob:http://127.0.0.1:5174/...`,可访问树仍为 `about:blank`。普通地图组件的可见性不能替代这个 HTML 的验收,渲染器返回成功也不能证明最终视觉正确。已保留空白预览截图,未将此项计为通过。
进一步在内存中执行真实 `prepareGeneratedHtml`:11,269 字节输入变为 14,597 字节,原有 3 个脚本逐字保留、DOM id 与外链 URL 均不变,新增兼容脚本语法有效。暂未发现生成器或预处理破坏 HTML 的证据;故障停在预览加载/Blob 导航阶段,具体原因未确认,不将其归为已知浏览器限制,也不宣称已修复。
界面还复现了 TDesign 新手引导闲置时的 `reading 'element'` 异常:`current=-1` 时其 resize 监听仍读取不存在的步骤。简洁模式与智能体两处包装组件已改为只有有效步骤才挂载 Guide。浏览器复测了文件面板开关、侧栏切换、手动启动、下一步、跳过,未再出现新的同类异常;完成/跳过的持久化语义保持不变。
## 合并后回归
- 完整 harness:274/274 通过,53.07s;包含前述技能及 Todo 子集,不重复累加。
- 模型并发配置专项:10 项通过;种子技能资源:4 项通过。
- 前端流式恢复专项:9 组共 44 项通过;待办可见性及相关消息分组:12 项通过。
- 全量前端构建和类型检查最初并行运行时,系统空闲内存降到约 17MB,因此主动停止该轮类型检查,改为串行执行;该轮中断不作为代码失败。
- `pnpm build` 通过(10m25s,包含前期资源争用,有大 chunk 警告)。其后新增的两个 Guide 挂载条件已通过单独语法检查和真实浏览器回归;另补齐问题导航抽取后的类型导入,不改变生成代码行为。
- 最终 `pnpm typecheck` 仍未通过,共 73 项原有诊断;与测试前本地 `hang-typecheck.log` 的 75 项逐条比较,减少了消息分组测试的 2 项,没有新增诊断。本轮发现的 `QuestionItem` 类型导入遗漏已经修正,复跑后消失。剩余问题包括 `nextra` 依赖、旧 JSX 类型和既有组件/测试类型,未扩大范围处理,不能标记全量类型检查通过。
## 本地证据和复测入口
详细证据仅保留在 `.runtime/test-results/20260928-local-qa/`,不提交模型凭证、问答日志、测试数据库、构建 ZIP 或技能临时大目录:
- `qa-concurrency-results.json`:逐轮时间、结束事件、答案检查和清理结果。
- `qa-concurrency-20-results.json`、`harness-full.xml`:20 个独立用户问答和完整 harness 回归。
- `knowledge-stable-recheck.json`、`knowledge-library-report.md`:知识库与资料库稳定复测及限制。
- `skills-benchmark-paired.json`、`skills-findings.md`:同机旧/新刷新配对;“旧逻辑”在隔离进程禁用新合并函数回放,不改服务源码。
- `philippines-html.json`、`large-skill.json`:旧页面技能能力缺口与公文技能真实调用。
- `philippines-map-ui.png`:普通地图真实浏览器渲染。
- `cognitive-philippines.json`、`cognitive-skill-probe.json`:最新技能真实完整问答及渲染器专项。
- `cognitive-preview-ui.png`:最新 HTML 在本轮内嵌浏览器出现空白的实际截图。
- `frontend-build.log`、`frontend-typecheck-final.log`:全量构建与最终类型检查。
提交的回归入口包括 `packages/harness/tests/test_skill_view_refresh_coalescing.py`、`test_skill_view_waits.py`、`test_sandbox_command_liveness.py`、`test_run_completion_timeout.py`、`test_todo_reminder_visibility.py`,以及前端 `control-timeout`、`stream-terminal-recovery` 和 `todo-reminder-visibility` 测试。
@@ -1,358 +0,0 @@
# 技能并发与流式修复:配置、前端包与验收说明
日期:2026-09-27(2026-09-28 补充高并发运行配置)。
本说明对应本次提交的修改,包含模型流式兼容与恢复、React #185 错误处理和已完成的最小技能示例,
以及可选的技能视图复用、版本缓存、模型计时日志队列和 Gateway 线程池扩容。
部署前通过 `git log -1` 核对代码提交;仅修改配置或替换旧包不能确认已部署本次修复。
## 1. 先确认需要更新什么
- **后台代码也要更新**:四个新开关需要新版后台读取。只换前端 dist 或只把字段写进旧版 config.yaml 不会实现后台优化。
- **前端**:使用本说明末尾的 ZIP,里面是完整 `dist/`,不是源码或 node_modules。
- **仓库运行配置已开启优化**:两份 config.yaml 的四个开关均已显式设为 `true`。但已有服务器的持久化/外挂配置不会被仓库自动覆盖,仍需手工同步。
- 开启线程池开关后可将上限调整为 100,但不提高模型服务商配额、不启用多 worker。
## 2. .env 需要修改哪些项
后台启动所使用的 `.env` 保持或修改为:
```dotenv
# Gateway 进程数,不是线程池大小;当前内存流/运行管理器必须单进程。
GATEWAY_WORKERS=1
# 默认就是 0;显式写 0 可防止误用不安全的多进程覆盖开关。
DEERFLOW_ALLOW_UNSAFE_MULTIWORKER=0
# Gateway asyncio 线程池上限;还必须打开下一节的 asyncio_thread_pool_enabled。
DEER_FLOW_ASYNCIO_THREAD_POOL_SIZE=100
```
适用于已更新的 `scripts/start_backend-online.sh` 和 `offline-backend-20260512/start_backend.sh`。
若通过自定义服务直接运行 Uvicorn,也应确认实际命令是单 worker;仅修改 .env 不会改变硬编码的启动命令。
启动环境中已导出的同名变量可能覆盖 .env,需一并核对。
前面三个技能/日志优化没有独立环境变量,它们配置在下一节的 `config.yaml`。
线程池上限变量现已真正接入;修改 .env 后必须重新启动后台,Docker 应通过现有启动脚本重新创建容器,
单纯 `docker restart` 不会更新容器创建时注入的环境变量。
其余模型地址、密钥、数据库连接等保留服务器原值,不用本机 .env 覆盖生产文件。
### 100 个线程与环境变量优先级
`GATEWAY_WORKERS=100` **不是**把工具线程池调成 100,而是启动 100 个进程,当前部署不要这样设置。
`DEER_FLOW_ASYNCIO_THREAD_POOL_SIZE=100` **已经实现**,兼容别名 `DEERFLOW_IO_THREADS=100`,
两者任选其一即可。开启线程池开关后,按以下顺序取第一个非空值:
1. `DEER_FLOW_ASYNCIO_THREAD_POOL_SIZE`(正式变量)
2. `DEERFLOW_IO_THREADS`(兼容别名)
3. `config.yaml` 的 `runtime_performance.asyncio_thread_pool_size`(默认 100)
有效范围为整数 **1..1024**。选中环境变量的值非法时启动失败并提示,不会静默退回默认小线程池。
开关关闭时不读取环境变量来改变线程池,保留 Python 原默认。已有正式变量时,修改别名不会覆盖它。
线程按需创建,100 是上限,不会预先常驻启动 100 个线程。
## 3. config.yaml 新增配置
在实际加载的 `config.yaml` **顶层**配置这一段,不能缩进到 `models`、`sandbox` 或 `skills` 内,
也不要重复定义两个 `runtime_performance`。下面是程序在字段缺失时的兼容性默认值;
当前仓库的两份可运行配置已使用后文的高并发开启值:
```yaml
runtime_performance:
# 一次工具调用内只获取一次已验证技能视图,默认 false。
skill_view_reuse_enabled: false
# 版本未变时复用技能视图,默认 false。
skill_view_cache_enabled: false
# 模型计时日志使用独立队列,不争抢耗时工具线程,默认 false。
model_timing_nonblocking_enabled: false
# 是否覆盖 Gateway asyncio 默认线程池,默认 false。
asyncio_thread_pool_enabled: false
asyncio_thread_pool_size: 100
```
如决定启用本次四项优化并将线程池上限设为 100,改为:
```yaml
runtime_performance:
skill_view_reuse_enabled: true
skill_view_cache_enabled: true
model_timing_nonblocking_enabled: true
asyncio_thread_pool_enabled: true
asyncio_thread_pool_size: 100
```
四个开关独立生效,可以单独开关。关闭/省略对应项时,对应的性能优化走原实现。
这四项不控制模型协议兼容修复或前端错误处理;全部关闭不等于回退所有代码。
为了让已有模型实例和所有后台进程配置一致,修改后重启后台;回退也是改回 `false` 后重启。
### 确认没有改错配置文件
- 已设置 `DEER_FLOW_CONFIG_PATH` 时,以它指向的文件为准;Docker 内该值必须是容器内可访问路径。
- 本仓库包含 `offline-backend-20260512/config.yaml` 和 `offline-backend-20260512/backend/config.yaml`;
两份已同步为高并发开启值,但服务器要修改的仍是启动时实际加载/挂载的那一份。
- 启动日志 `Loaded AppConfig from ...` 可确认路径,`RUNTIME_PERFORMANCE` 可确认实际开关值。
## 4. 开启后做了什么,没做什么
### 单次调用复用
同一次 `read_file`、`ls`、`glob`、`grep`、`bash` 等工具执行期间,技能检查、沙箱初始化、
路径替换和输出脱敏共用一份已验证视图;退出调用后清理作用域,下一次调用重新验证。
不会把一个问答最初的技能启停状态一直沿用到结束。
### 技能版本缓存
每次核对启停 JSON 内容、已知源/目标文件和目录的元数据及标记。
版本一致时不重新发现/解析全部技能、不复制文件、不持有全局刷新锁。
新增、编辑、删除、启停及支持文件变化触发重建,并保留跨进程锁合并并发刷新。
没有采用会延迟下线的 TTL 缓存;下一次工具调用能发现下线或无效配置并拒绝访问。
已经开始执行的工具不因此被强行中断。
缓存仅用于标准 `LocalSkillStorage`,自定义存储实现/子类保守回到原刷新路径。
同一 Gateway 进程内,仅在多个热命中调用真正重叠时合并为一次元数据校验;
该批调用结束后结果立即丢弃,新调用仍重新校验。启停文件哈希不同的调用不会加入旧校验,
校验异常会对该批调用统一 fail-closed,且不会阻止后续调用重试。
热路径仍有 O(文件数) 元数据校验,慢磁盘/网络挂载仍可能耗时;这不是“所有文件操作零开销”,
也没有把受锁保护的重建变成无锁写入。
### 模型计时日志
仅轻量计时/入队在回调中执行,日志 I/O 由独立线程消费,不占工具共享线程池或事件循环。
队列上限 4096 条;日志端长期阻塞时会丢弃诊断并在恢复后汇总告警,不无限积压或阻塞模型输出。
退出时最多等待 0.5 秒尽力刷新,异常退出可能丢失尾部日志。
这是 `ModelTimingCallback` 的优化,不会改变其他回调(如 RunJournal、可选追踪插件)、
子智能体调度池、数据库池或模型上游的连接/速率限制。不能据此保证 100 个会话同时生成。
### Gateway 工具线程池
开启 `asyncio_thread_pool_enabled` 后,在后台启动时、LangGraph 初始化之前设置当前
Gateway 事件循环的默认执行器。同步工具、该循环的 `asyncio.to_thread` 等可使用最多 100 个槽位。
关闭时完全不替换默认执行器;退出时由拥有该事件循环的服务运行器清理。
这不是 AnyIO 的同步 HTTP 路由线程池,也不改变子智能体专用池或独立事件循环的默认池。
线程池扩大只能减少可并行 I/O 的排队,不能让同一把技能锁同时被多人持有,也不会增加模型端的生成配额。
## 5. 日志检查
确认加载日志类似:
```text
RUNTIME_PERFORMANCE skill_view_reuse_enabled=True skill_view_cache_enabled=True model_timing_nonblocking_enabled=True asyncio_thread_pool_enabled=True asyncio_thread_pool_size=100
```
线程池最终是否生效,以另一条启动日志为准(进程 id 随实际启动变化):
```text
GATEWAY_ASYNCIO_EXECUTOR enabled=true max_workers=100 source=DEER_FLOW_ASYNCIO_THREAD_POOL_SIZE pid=12345
```
如果仍显示 `enabled=false max_workers=python_default`,说明线程池开关没打开或改错了配置文件,
不是已经调整到 100。改环境变量后若日志仍取旧值,检查是否重建了 Docker 容器及实际 env-file。
查看以下日志:
| 日志 | 用途 |
| --- | --- |
| `GATEWAY_ASYNCIO_EXECUTOR` | 实际线程池开关、最终上限、配置来源和进程 id;关闭时显示使用 Python 默认,不虚报 100 |
| `SKILL_VIEW_CACHE status=refreshed` | 发生重建;包含 `lock_wait_ms`、`refresh_ms`、`total_ms` 和条目数 |
| `SKILL_VIEW_CACHE status=joined` | 等待期间其他线程/进程已完成重建,本次直接复用 |
| `SKILL_VIEW_CACHE status=hit` | 缓存命中;正常命中为 DEBUG,超过 500ms 的慢命中为 INFO |
| `SKILL_VIEW_CACHE status=failed` | 刷新失败,旧能力不可继续使用,需要排查配置/磁盘 |
| `LLM_CONNECT_START/OK`、`LLM_REQUEST_DONE/FAILED` | 模型调用生命周期、首块和总耗时 |
| `LLM_CALL_RETRY/FAILED`、`OPENAI_TOOL_STREAM_SUMMARY` | 模型重试/兼容处理诊断 |
| `LLM_TIMING_LOG_DROPPED` | 日志队列曾满;检查日志磁盘/采集端速度 |
如需查看正常缓存命中,可短时设置顶层 `log_level: debug`;排查后恢复 `info`。
首块耗时不等于纯网络连接等待,仍包括上游排队、模型处理等阶段。单次 curl 成功也不能证明并发容量足够。
本次日志不记录技能正文、模型正文或 API 密钥。
## 6. 前端替换与回退
1. 先备份服务器当前前端目录和 `runtime-config.js`,并备份实际后台 .env/config.yaml。
2. 校验下载 ZIP 的 SHA-256 与本说明记录一致,再解压到一个新的发布目录。
3. ZIP 包含 `dist/`;Web 根目录应指向其内部,确保根下直接能找到 `index.html`,不要误放成 `dist/dist/`。
4. **保留/恢复服务器自己的 `runtime-config.js`**。核对生产后台地址、认证和嵌入参数;不要把构建机默认值当生产配置。
也不要覆盖生产 .env 的密钥与数据库配置。恢复 runtime-config 后其单文件哈希自然与原包不同。
5. 更新后台代码并按需设置四个开关,使用现有部署方式重启后台,再切换前端发布目录。
6. 刷新浏览器缓存后检查普通问答、智能体问答、技能示例、读取技能、生成文件以及离开后重新打开正在生成的会话。
7. 如需回退性能优化,后台关闭相应开关并重启,无需删除技能文件或技能缓存目录。
如需回退模型协议或前端修复,须恢复对应的已备份代码/前端发布目录,单独关闭性能开关不够。
正式 Linux AMD64 离线镜像/发版仍通过独立的 `knowledge-base-bj/deerflow-offline-deployment`
仓库流程执行;本次前端 ZIP 不是完整后台离线镜像。
## 7. 本地验证结果与限制
### 后台
- 提交前最终专项:技能/线程池/日志/启动配置及技能老回归 **166 项通过**;模型适配、错误分类、
诊断失败保护、SSE 响应头、会话计时与真实 transport **123 项通过**(两组不重叠,共 289 项)。
对应修改模块与测试 Ruff 通过,harness 未增加对 app 的反向依赖。后续没有执行生产模型并发压测。
- 本次技能复用/缓存/配置、日志回调与相关技能目录、大文件安全专项:**79 项通过**;
又补充 1 项开关关闭/重新开启的回退测试,通过缓存文件全部 13 项回归,合计 **80 项**。
- 模型工具参数流/推理流、错误恢复、SSE 传输和启动 worker 校验另 **76 项通过**;相关专项共 **156 项通过**。
- 后续新增线程池接入与配置专项 **45 项通过**(与前述配置测试有重叠,不相加充当独立总数):
覆盖默认关闭、两个环境变量优先级/别名、非法值拒启、启动顺序,以及实际 **24 / 100 个本地阻塞任务同时执行**、
退出后线程全部清理;新模块和相关测试 Ruff 检查通过。另一次联合技能/日志/启动配置回归 **88 项通过**。
该测试只验证本地线程池,不是 100 路模型压测。
- 线程池接入后再次尝试后台全量测试(首次失败即停止):**604 通过、2 跳过、1 失败**,
仍停在修改前已复现的 `test_llm_metrics.py::test_middleware_records_success_with_speed`,不是全量通过。
- 冷启动 8 线程并发只构建一次;真实第二进程复用持久化清单、不再发现技能。
- 下线/无效配置、源文件变更、同长保留 mtime 编辑、目标篡改、Windows junction 保护均有回归覆盖。
- 真实 LangChain 异步模型测试证明:默认工具线程池占满且日志处理器阻塞时,启用计时日志优化仍可开始、输出 token 并结束;未调用真实模型服务。
- 修改后尝试全量测试,设置失败 5 项停止:**871 通过、2 跳过、5 失败**,并非全量通过。
失败包括 `test_llm_metrics.py` 的 3 项记录时序断言、既有 Wiki `auto_sync` 配置与测试预期不一致、
`test_model_management.py` 的 thinking 参数预期不一致。首项在本轮修改前即已复现;
本轮没有修改指标中间件、模型工厂或 Wiki auto_sync 设置,不为过测试擅改这些业务配置。
- 本次针对 #185/MD 的追加回归:模型真实 SDK 回放、工具参数、思考字段、日志、配置、线程池、
错误中间件和传输联合 **145 项通过**。其中新增 SDK 回放 19 项,覆盖 8 种写文件形态,
确认 JSON 尚未闭合时部分 MD 已传出、最终工具名称和参数正确;没有连接线上模型。
### 合成性能对比
Windows 11 / Python 3.12.13,本机临时目录:150 个技能、450 个文件,各模式预热一次后串行 10 次。
旧刷新平均约 **3133ms**,缓存命中平均约 **806ms**(本次约 3.89 倍);
`load_skills` 从 10 次降为 0 次。临时数据已清理。
这不是生产 Linux 性能结论,也不是多人访问模型的承载压测。
### 前端与交付包
- 提交前最终前端专项 **60 项通过**(原 57 项,加同 reader 续接/新页面重播与迟到事件隔离 2 项、
最小技能示例 1 项);真实生产 React 浏览器错误边界测试再次通过。
- 最终全量类型检查仍有既有 **75 个诊断**,本次变更文件无新增诊断;记录在
`.runtime/frontend-final-typecheck-20260927.log`。不要把构建成功等同全量类型检查通过。
- 前端本次流式恢复、React #185 分类、技能示例、流式预览及相关权限等 **32 项专项通过**;
修正新增测试文件一处 `.ts` 导入导致的 TS5097 后,相关 16 项再次通过。
- 最新追加前端专项 **57 项通过**,含真实 SDK SSE → 文件参数 → MD 预览;旧 16ms 设置在连续流中
没有通知刷新,修复后在 JSON 尚未闭合时持续更新。真实 Chrome + 生产 React 中用循环 layoutEffect
触发 #185,验证静态友好兜底、无自动重挂、点击重新载入后恢复。
- 最新 `pnpm build` **通过**:Vite 13,853 个模块,8 分 49 秒;存在大于 500KB 的 chunk 提醒,不是构建失败。
构建日志 `.runtime/frontend-final-build-20260927.log`;本次修复重新打开会话的游标边界后已重新打包。
- 前一版临时 localhost 静态 HTTP 烟测 **通过**:入口 HTML 及引用的主 JS/CSS/runtime 等 5 个资源均 200,
响应字节 SHA-256 与磁盘一致,没有缺失资源;烟测服务已关闭。
- 最新 ZIP 中 **886 个文件**均逐文件比对大小和 SHA-256,与本次 dist 一致;入口/CSS 的 99 个本地资源引用全部存在。包内无 `.env`,
入口为 `dist/index.html`,包含 `dist/runtime-config.js`。
- 全量 `pnpm typecheck` **未通过**:复测还有 **75 个诊断、涉及 29 个本次未修改文件**,
包括现有 nextra / `@codemirror/state` 依赖、旧测试及 legacy QA 类型问题;
本次新增测试文件的 TS5097 已修正并复测,本次前端变更文件无类型诊断。
完整本地日志为 `.runtime/qa/frontend-delivery-typecheck-20260927.log`;
不能把生产构建通过表述成整个项目类型检查通过。
追加修复后本次产品变更文件无全量类型诊断,新增测试及依赖专项 TypeScript 检查为 0 诊断。
- 附加 legacy Chrome CSS 检查 **未通过**,报三个本轮未修改文件
`legacy-html-preview.test.ts`、`legacy-html-preview.ts`、`SolutionProjectLanding.tsx` 中的现代颜色函数字样;
没有报本次 dist CSS 缺失回退,也不能据此宣称完成旧浏览器端到端兼容验收。
交付 ZIP(仓库根目录):
```text
deerflow-frontend-dist-20260927-master-final.zip
```
- ZIP 大小:35,869,210 字节(约 34.2 MiB)。
- 此包替代 `deerflow-frontend-dist-20260927-191207-185-stream-fix.zip` 及更早版本;旧包保留,但不包含最终的游标作用域修复。
- 解压后文件总大小:66,347,693 字节。
- ZIP SHA-256:
```text
7E4C1525BDEB686161FFF5AED12D36087407BBF4F472B87E78CA04DADD1DF371
```
Linux 可用 `sha256sum deerflow-frontend-dist-20260927-master-final.zip`;
Windows 可用 `Get-FileHash -Algorithm SHA256 .\deerflow-frontend-dist-20260927-master-final.zip`。
未连接生产环境进行真实多人模型问答端到端验收,不能宣称所有线上卡顿已被实测消除。
## 8. 关于 20 人同时使用
当前不能承诺 20 人同时问答一定流畅。本次验证了本地代码路径和构建产物,并没有验证你的两台服务器、
上游模型地址/API key 配额、数据库/磁盘及实际技能耗时在 20 路负载下的容量。
部署新版后台、明确开启所需开关后,先在测试环境按 5 → 10 → 20 个独立会话逐级测试:
1. 纯聊天和包含技能读取/写文件的问答分开测试,保持提示长度和输出规模接近真实业务。
2. 每级记录成功/失败/超时数、首字和总耗时的分位数,以及技能 `lock_wait_ms/total_ms`。
3. 同步查看模型端 429/503、排队数量/首 token 延迟,以及应用 CPU、内存、磁盘和数据库等待。
4. 若上游只能并行处理少量请求,应用扩线程无法增加上游容量;应控制并发或扩容模型服务。
20 个在线用户、20 条运行中的问答和 20 个正在模型端生成的请求不是同一指标。
## 9. #185 与 MD 流式追加修复
用户已确认思考模式正常;本节针对仍出现的 #185 和 MD 预览卡住。
- 四个直接流入口统一使用 `STREAM_RENDER_BATCHING=true`,避免安装版本 SDK 的数字 16ms
尾部防抖不断推迟 UI 刷新;保留异步批处理,不改成每个片段同步强制渲染。
- #185 流错误不会再按模型异常直接显示原始错误串;同一轮最多一次自动恢复,重复失败暂停重连,
不主动取消后台任务,不循环重新发送问题。友好提示 30 秒去重。
- 真正渲染/commit 阶段的 #185 由页面错误边界接住,进入静态提示,只能手动重新载入;
不吞其他错误。控制台 `react_ui_render_error` 保留组件堆栈,帮助定位未知的线上循环组件。
- 恢复游标与当前页面的消息累积器绑定:同一页面断线续接不重复拼接工具参数,离开后重新打开或
切换会话则完整重播,不能复用全局旧游标跳过正文前缀;旧 reader 的迟到事件也不污染新页面。
- 后端兼容重复工具名称,避免 `write_filewrite_file` 使工具路由和预览识别失效;
`OPENAI_TOOL_STREAM_SUMMARY repeated_tool_names` 可确认是否命中。也修复了空 `error:{}` 被误判失败。
- 诊断日志写入失败不会覆盖真实模型异常、取消或成功结果。错误脱敏后仍在内存中识别上下文超限,
并识别 `invalid_api_key` 等结构化认证错误,防止本应修剪上下文或停止重试的请求反复排队。
- **实时预览和物理落盘不同**:模型还在生成参数时展示虚拟 MD 内容;参数完整、工具校验通过后,
`write_file` 才正式写沙箱文件。此次不把未完成的 JSON 直接写进最终文件。
本地已经复现并修复上述具体缺陷,但没有线上原始流/组件堆栈,不能保证它们解释全部生产故障。
## 10. `threads` 创建慢:数据库路由与阶段耗时
`POST /api/threads` 会先查/写应用数据库的 `threads_meta`,再调用检查点存储写入空 checkpoint;
它不需要请求模型,也不会在创建时遍历所有旧问答。
当前仓库部署模板是 `database.backend: mysql`,同时 `checkpointer.type: postgres`、
`checkpointer.use_postgres: false`。如果服务器保持这些值且没有 `DEER_FLOW_USE_PG_CHECKPOINTER`
覆盖,实际是 **MySQL 元数据 + SQLite 检查点**,清理 PostgreSQL 不会加速这条链路。
本地开发配置则是 SQLite。线上以实际加载的配置和环境覆盖为准,不凭数据库连接串是否存在判断。
新建/搜索接口新增 `GATEWAY_OPERATION_TIMING` 日志和 `Server-Timing` 响应头,
浏览器 Network 的响应头也能看到,不必先拿服务器日志:
- `metadata_lookup` / `metadata_create`:应用元数据查询/写入。
- `checkpoint_create`:检查点创建,包含 saver 锁/连接池等待和数据库写入,不能等同为纯 SQL 时间。
- `metadata_search`:会话列表的元数据查询。
- `handler_total`:进入处理函数后的耗时;**不含进入函数前的事件循环/鉴权/代理排队**。
模型图构建仍保持原来的任务上下文。新增 `AGENT_BUILD_TIMING`:超过 500ms 以 WARNING 记录,
正常为 DEBUG。已在本地复现同步慢工厂阻塞同事件循环的其他请求,但不能直接裸搬到线程:
延迟工具注册上下文需回传,MCP 初始化存在跨事件循环约束。此处目前是定位日志,不是已经消除阻塞。
本机安装的 SQLite saver 和 PostgreSQL saver 都存在实例级串行锁;后者使用连接池也不代表
同一个 saver 自动并行处理所有检查点。扩大 asyncio 线程池不解除此锁。
尚未取得线上分阶段耗时,因此不能承诺新建 10 秒已经根治,也不能承诺归档即可解决。
新增计时与真实 SQLite 锁测试、已有分析项目/浏览器内部创建入口联合 **43 项通过**,
其中计时专项 14 项;这是本地回归,不是线上延迟验收。
## 11. 30 天已结束会话的 PostgreSQL 归档 SQL
归档脚本单独交付,不进入本源码仓库,也不在启动时执行。使用 `pg_checkpoint_archive.sql` 搬移,
`pg_checkpoint_restore.sql` 按提交批次恢复;两者需与 `pg_checkpoint_common.sql` 放在同一目录。
应用数据库在 MySQL / PostgreSQL 的候选只读导出分别为
`mysql_checkpoint_candidates.sql` / `pg_checkpoint_candidates.sql`。
按用户确认,候选仅包括 30 天未更新、所有运行已结束的会话,排除正在运行、待处理和等待用户输入的会话。
PG 检查点没有应用会话终态字段,因此不能只按 `checkpoint.ts` 猜测,必须先从应用元数据导出候选 ID。
脚本仅在确认实际启用 PG、全部写入服务已停、备份可恢复及双读回退关闭后允许提交。
默认是预览/回滚;提交时三张原始表的全部 namespace 一起搬入新归档 schema,逐行校验后才删源行,
恢复时不覆盖同 ID 的新数据,归档副本保留。不删除沙箱文件。
**范围与风险**:这是 PG 检查点冷归档,不是完整应用归档。它不搬 MySQL `threads_meta/runs`,
因此旧会话列表入口可能仍在,但归档正文需要恢复后才能读取/续聊。归档到同一库的新表也不保证减少总磁盘占用。
SQL 的验证记录与具体执行命令见单独交付包的 README;部署前仍须在生产备份恢复的隔离副本演练。
不要跳过预检直接在生产提交。如果线上仍为 SQLite,这组 PG SQL 不适用。
独立包 `deerflow-db-archive-20260927.zip` 含 SQL、README 和复验测试,不含数据库数据、连接凭据或数据库二进制。
已在 PostgreSQL 16.15 + 安装的 LangGraph checkpoint 3.1.2 原始建表结构上通过 13 项真实执行和 14 项静态检查;
未执行真实 MySQL 候选导出,详见独立包 README。ZIP 共 9 个文件、20,983 字节,SHA-256:
```text
E90A189DA7D7032527EED7CEC9B51DE1A30FB6D48B4382CE06AF1C287B670F59
```
@@ -1,73 +0,0 @@
# 问答停在执行命令或读取技能:排查与修复
日期:2026-09-28。
本次检查针对普通问答和智能体问答:页面停在工具步骤,上游模型没有收到下一轮请求。
以下是代码审查和受控回归确认的触发路径;尚未收到具体生产对话 ID 和现场日志,不能据此认定某次现场故障只有一个根因。
## 已修复的等待路径
| 位置 | 原来的触发条件 | 当前行为 |
| --- | --- | --- |
| LocalSandbox 命令执行 | `subprocess.run` 超时仅终止外层 shell,后代仍持有输出管道;Windows 超时收尾继续无期限 `communicate` | 独立进程组、关闭交互输入、临时文件采集输出;超时清理进程树并限制回收等待 |
| 技能视图刷新 | 进程锁、跨进程文件锁和等待并发校验结果均没有统一等待上限 | 等待最多 30 秒后抛出明确工具错误;不删除正在执行的刷新,不使用未经校验的旧视图 |
| AIO 沙箱 | 上次命令未返回时,后续命令或文件操作无限等待同一把锁 | 锁等待 30 秒后失败;不抢占旧请求的锁,不自动重复执行命令 |
| 文件分段读取 | 超长单行先读完整行才裁剪;FIFO/设备文件可能一直等数据 | 达到当前行输出预算即返回;本地读取用非阻塞打开并检查普通文件,远端分段读取同步限制 |
| 前端结束恢复 | 后端已 success/error,但旧 SSE 仍开着,SDK `isLoading` 一直为真;整段 SSE 期间的 `sendInFlight` 又把同一轮结束快照丢掉 | 核对轮次及运行 ID 后清理重连标记、关闭本地 reader、应用结束快照;不因此取消后端或覆盖新一轮 |
| 前端恢复查询 | `/runs`、检查点或历史请求悬挂,占着 single-flight 恢复槽 | 普通 SDK 请求设置 30 秒超时;恢复失败仍保留后续检查机会,SSE 不受此总时长限制 |
| 后端结束收尾 | 图已返回,但检查点检查、状态写入、日志刷新或标题同步永远不返回,导致 `end` 发不出去 | 终态检查、终态状态写入分别有 10 秒预算;后续元数据收尾共享 10 秒预算,独立 finally 发出 `end` |
技能锁超时走原有工具错误处理链,模型可收到失败结果并决定后续操作;不会把“超时”伪装成成功。
元数据收尾超时只发生在图已经结束后,不给整个研究/子智能体执行增加统一短时限。
终态检查点超时会报告运行失败,不能直接当成模型成功。
## 配置和上线
本次需同时更新后端代码和前端构建产物,重启后端后生效。只刷新页面或调线程数不能替代修复。
本次未操作生产服务、未发布前端包;正式离线发版仍使用独立的 `deerflow-offline-deployment` 仓库。
本地命令保留原来的 600 秒默认执行时限,新版允许在实际加载的配置文件中调整:
```yaml
sandbox:
# 合并到已有 sandbox 段中,保留 use、mounts 等既有字段。
command_timeout_seconds: 600
```
该字段只控制 LocalSandbox 命令执行,必须为有限正数。未配置仍为 600 秒;不要把它误认为模型请求超时。
命令输出每个流最多读入 1 MiB 头尾内容,再经过既有工具输出裁剪。
运行中的命令约每 100ms 检查累计捕获输出,超过 16 MiB 请求终止;这是采样护栏,不是磁盘硬配额。
正常退出后的显式后台进程需要自行重定向输出和管理生命周期。
前端已有的无业务事件检查窗口仍为 90 秒;这是启动后台状态核对的时机,不是宣判任务失败的时限。
30 秒控制请求超时不影响合法的长时间 SSE 和工具执行。
## 仍需现场证据区分的情况
- 磁盘/NFS 本身阻塞的刷新执行者仍可能卡在操作系统 I/O;本次限制的是其他调用的等待,不宣称能终止任意内核 I/O。
- 自定义技能脚本自身请求外部服务不返回,仍会等到本地命令时限;建议技能内各 HTTP 请求也设置连接/读取超时。
- 整个图中的第三方异步工具、模型前中间件和检查点操作没有统一的“无事件即取消”规则,避免误杀合法研究任务。
- 检查点回滚是实际数据修改,保持原有完成/取消语义,不把仍在执行的回滚丢到后台后开放下一轮。
- 已提交给数据库的单条写入未必能被驱动撤销;取消和新轮次检查可阻止旧清理继续发起后续写入,不能保证撤回已经执行的 SQL。
再次出现时,记录对话 ID、运行 ID、最后一步和时间,并对照上游请求日志、运行状态及
`RUN_COMPLETION_TIMEOUT run_id=... phase=terminal_checkpoint|terminal_status|metadata_cleanup`。
技能锁超时会包含 `Timed out waiting for skill view ...`;沙箱命令超时会包含 `Command timed out`。
不要仅凭页面最后显示“读取技能”就断定仍在读文件,它也可能是结束消息没有传到浏览器。
## 回归入口
- 后端 `packages/harness/tests/test_skill_view_waits.py`:锁竞争和并发校验超时、失败后恢复。
- 后端 `packages/harness/tests/test_skill_view_cache.py`、`test_skill_view_tool_reuse.py`:既有启停与缓存安全性。
- 后端 `packages/harness/tests/test_sandbox_command_liveness.py`:真实父子进程、输出、非交互输入及特殊文件/长行。
- 后端 `packages/harness/tests/test_run_completion_timeout.py`:挂起的结束收尾、取消、新一轮隔离及正常长图执行。
- 前端 `src/core/api/control-timeout.test.ts`、`src/core/threads/stream-terminal-recovery.test.ts`:控制请求超时及真实 SDK reader 恢复。
- 前端既有 `stream-recovery`、`stream-display`、`stream-reasoning-replay`、`stream-cursor` 测试继续验证断流重连和消息显示。
## 本机验证结果
- 后端 `python -m pytest packages/harness/tests -q`:**263 passed**。旧同步日志断言补了显式测试配置,避免当前启用异步日志时与后台队列竞速;异步日志仍由独立测试覆盖,未改实际运行配置。
- 前端八个相关测试文件打包后用 Node test runner 执行:**31 passed**;新增测试类型修正后其中三个新增用例再次通过。
- 修改的后端代码和测试通过 Ruff;`git diff --check` 通过。
- 完整前端类型检查未通过:**75 个 TypeScript 错误**,均在本次未修改的文件,涉及 `nextra` 缺失、旧 JSX 类型、既有测试类型等。本次修改文件及新增测试无诊断。详细输出保留在 `frontend-web/.runtime/hang-typecheck.log`(本机文件,不作为发版资产)。
- 命令进程树测试在 Windows 使用真实子进程;Linux 进程组分支已审查,但本机未做 Linux 实跑,AIO 未连接实际容器。未用生产模型调用或真实业务技能执行验证。
-3
View File
@@ -59,9 +59,6 @@
# 简介模式左侧菜单类型:与菜单管理页「简介模式」的类型 A / B 对应。两套网页分别填 A 或 B。
# 不填或留空时按类型 A,继续使用原来的简介菜单数据。
# VITE_COMPACT_MENU_TYPE=A
# 问答页「极速」模式:true=在模式菜单显示并直连大模型;false 或未设=隐藏。
# 部署后优先改 dist/runtime-config.js 的 VITE_TURBO_MODE_VISIBLE,刷新即可。
# VITE_TURBO_MODE_VISIBLE=false
# VITE_GITHUB_OAUTH_TOKEN=
# --- 官方 DeerFlow 风格页面入口(仅 Vite,不引入 Next.js)---
+7 -28
View File
@@ -1,34 +1,23 @@
# 我的项目
# 项目空间
入口:全量与简洁导航中的「我的项目」,路由 `/page/strategy/qa/projects`。旧地址 `/page/workspace/projects` 仅保留兼容跳转,不再展示独立入口或旧页面。
入口:全量与简洁导航中的「项目空间」,路由 `/page/workspace/projects`。
## 使用流程
1. 新建项目,选择普通问答、策略优选或方案生成。三类项目独立保存和展示,方案生成不会复用或标记策略优选项目。
1. 新建项目,填写名称,在问答、策略智能、方案生成中选择一种模式。
2. 选择项目默认智能体,填写目标、约束等项目说明。新建项目对话时仍可换用另一个可访问的智能体。
3. 创建后进入项目工作区。普通问答项目可包含多条独立问答;方案项目可包含多条方案记录。最近对话根据 `analysis_project_mode` 回到普通问答分组或方案项目。
3. 创建后进入嵌入式问答工作区,左侧保留普通聊天记录;项目对话也会出现在聊天记录中并返回所属项目。
4. 方案生成可从「工作流配置 · 报告结构」选择、启停、编辑、删除结构,选择后自动填充项目报告结构配置;也可直接编辑大纲及固定/弹性约束。
5. 策略智能项目保存默认 Strategy Lens;每轮依次进行问题重构、各 Lens 独立分析、策略辩论和方案生成,并分为「意图理解」「多视角策略分析」「完整策略方案」三栏。右栏以文档形式给出执行摘要、目标原则、分阶段行动、资源配置、风险应对、评估复盘、形成依据与备选策略切换条件;原始对话和引用仍可切换查看。
6. 策略智能对话底部提供改变约束、增删视角、重新推演和挑战当前策略快捷动作;项目主页面可直接添加或删除 Lens。
模式在创建后不可修改,前后端都不提供修改入口。项目、对话归属和智能体访问权限在服务端校验;方案结构及每条对话所选智能体也以服务端配置为准。
## 普通问答跨会话记忆
- 仅普通问答项目显示「跨会话项目记忆」。它只受项目自身开关控制,与系统「问答记忆」总开关相互独立;成功完成的会话会在后台整理,状态包括等待沉淀、整理中、已就绪和异常。
- 新会话提问时会召回同一账号、同一项目中其他会话的事实、决策、约束、偏好、术语与未决事项。不会读取其他项目或其他账号,也不会混用普通聊天/智能体的通用记忆。
- 项目设置和问答页头部均可打开「项目记忆」面板,查看精简快照、条目可信度/重要度和来源对话;支持手工新增、编辑、固定、删除、清空以及从当前项目历史对话重建。项目暂停后仍可清空已有数据,但不能重建。
- 编辑、删除或清空原对话时,服务端先让对应记忆失效,再修改消息;重建期间不注入旧快照。固定或手工条目在重建时保留,自动条目按来源 checkpoint 时间判断新旧,较早会话不会因后台任务晚完成而覆盖新的纠正。
- 交互问答在首包前使用有界关键词召回,避免等待远程向量编码;后台整理仍可写入向量供显式或离线检索使用,编码不可用不影响跨会话记忆。输入提示块有条数与 token 上限,历史内容只作为非指令资料,当前消息优先。
## 代码与运行
- `src/pages/AnalysisProjectsPage.tsx`:普通问答与方案项目的新建、设置、历史和工作台布局。
- `src/strategy-selection/StrategyProjectsPage.tsx`:「我的项目」三类项目列表及创建入口。
- `src/pages/AnalysisProjectsPage.tsx`:项目列表、新建、设置、Lens 配置、历史与工作台布局。
- `src/pages/analysis-projects/ProjectConversation.tsx`:现有聊天、研究进度、方案画布的项目级组合。
- `src/core/analysis-projects/api.ts`:Gateway 项目 API 与按账号隔离的缓存。
- `src/pages/analysis-projects/ProjectMemoryPanel.tsx`:项目记忆状态、快照、来源和管理操作。
- `src/core/analysis-projects/memory-status.ts`:总开关/项目开关、状态和按钮可用性映射。
- 后端:`/api/analysis-projects`,对话仍通过现有 `/api/threads/{thread_id}/runs/*` 流式接口发送;服务端从不可变归属读取项目配置。
启动新版 Gateway 后自动创建项目表。生产持久化依赖已配置的数据库;memory 模式中的项目随服务重启丢失。前端沿用仓库的 Vite 开发与构建命令。
@@ -43,14 +32,6 @@ python -m pytest tests/test_analysis_projects.py tests/test_deep_research_report
涵盖内存与 SQLite 存储、跨用户隔离、禁止修改模式、运行时覆盖伪造模式与知识库、更新配置、对话归属与失败清理、固定方案模板及知识库资料进入研究管线。
跨会话记忆专项:
```shell
python -m pytest tests/test_analysis_project_memory.py tests/test_analysis_project_memory_store.py tests/test_analysis_project_memory_runtime.py tests/test_analysis_project_memory_integration.py tests/test_analysis_projects.py -q
```
前端专项:`node --experimental-strip-types --test src/core/analysis-projects/memory-status.test.ts`,并执行 `pnpm build`。
部署前还需使用实际知识库和模型验证三类问答、流式断线续接及方案后续修改。接口模拟与单元测试不能替代真实模型联调。
## 2026-09-14 我的项目与知识库验收修复
@@ -59,11 +40,9 @@ python -m pytest tests/test_analysis_project_memory.py tests/test_analysis_proje
- 简洁模式的「我的项目」列表、策略工作台和普通问答项目恢复工作区功能导航;窄屏提供展开菜单按钮。
- 普通问答先创建具名项目,再在项目内创建多个对话。列表读取 `/api/analysis-projects` 的 `qa` 项目,不再读取、标记或自动归入全局普通聊天。
- 项目设置更新保留既有知识库绑定。旧「项目空间」入口已移除并跳转「我的项目」;普通问答路由为 `qa/projects/groups/*`,方案生成路由为 `qa/projects/solutions/*`。
- 项目设置更新保留既有知识库绑定。原「项目空间」与官方入口继续可用;我的项目下问答路由为 `qa/projects/groups/*`。
- 策略生成卡片统一先显示思考/执行过程,再显示正文;评判、方案及展开视图沿用相同顺序。
- 策略优选工作台拆为三步:意图与任务定义、策略生成与智能评判、综合方案生成。第二步不重复展示问答记录,突出当前任务并扩大策略回答、评判正文;第三步将生成过程默认收起并为方案正文保留固定可视空间,集中完成方案生成、Markdown 编辑、项目保存以及 Markdown/Word 直接下载。保存后的项目卡也提供 Markdown/Word 下载;`?module=solution` 直接进入第三步,历史方案即使任务已修改仍可查看下载。
- 资料库把已完成的策略优选综合方案作为独立「策略生成」来源展示,并标注具体策略项目名称;条目可回到策略项目第三步,也可直接下载 Markdown/Word。普通策略项目线程生成的文件沿用原文件下载链路并显示同类来源标识。
- 方案生成使用独立项目和固定报告结构,通过 `deep_research_report` 直接生成并打开方案画布;策略优选项目不再出现在方案生成分类中。
- 完成评判但尚未勾选策略的项目可以从方案列表进入,在工作台选择后生成;已保存方案在任务修改后仍可打开。旧列表请求不再覆盖新请求状态。
- 知识库管理页读取上游最新目录,避免远端删除后命中旧缓存;检索调用仍共享短期目录缓存。
- 普通用户访问尚未初始化的助手知识库时显示明确空态及刷新按钮。
@@ -1,7 +1,5 @@
# 技能知识归纳与“知识梳理”助手知识库
助手知识库的目录、正文、来源和任务记录读取已提交快照,不等待后台导入的全局写锁,也不重复统计整库内容。导入仍在提交前完成实体及 Wiki 对齐,旧数据在检索、导出时保留兼容对齐。页面和展示权限的读取支持取消及 30 秒超时,失败显示可重试错误,避免一直加载;大目录分页失败后停止自动续页并保留已加载正文。来源列表仅在打开「来源与同步」或「导入 / 导出记录」时请求。
管理员在「技能管理 → 技能知识归纳」中选择一个或多个技能、一个或多个目标,系统按“技能 × 目标”创建后台任务。界面提供总体进度、单项失败重试、实体/关系审核、绑定重归纳、自动同步和两种解绑动作。技能列表通过一次 bindings 查询展示归纳目标,避免逐技能请求。
扫描仅处理知识资料。代码、脚本、锁文件、密钥文件以及 Markdown 代码块不会进入上传、摘要、提示词或知识指纹;ZIP 只读取逐项验证通过的知识成员。自动监听只比较该知识指纹,所以纯代码改动不会产生 stale 状态。
@@ -1,977 +0,0 @@
# 多智能体会商功能与接口梳理
## 1. 文档范围与入口
本文梳理的是常规「多智能体会商 / 圆桌规划」页面 `RoundtablePlanningPage` 的完整三步流程:
1. 任务意图理解
2. 多智能体研讨
3. 方案结果展示
主入口为 `/page/workspace/qa/multi-agent-roundtable`。它也可由任务深链 `3qfx-A`、`rwfx-A`、`xdfx-A` 打开,分别挂载在任务管理下的三情、任务、行动业务路由中;另有 `#/embed/roundtable` 嵌入入口。
任务深链会预填任务名称、任务目标、业务编码和任务 ID,并自动选择对应业务链:
| 深链 | 业务编码 | 嵌入路由 |
| --- | --- | --- |
| `3qfx-A` | `3Q` | `/page/strategy/task-management/plan-task-sentiment/roundtable` |
| `rwfx-A` | `6BF` | `/page/strategy/task-management/plan-task/plan-task-fx/roundtable` |
| `xdfx-A` | `7BF` | `/page/strategy/task-management/plan-task/plan-task-action/roundtable` |
> 本文不展开独立的阵位会商,以及仅展示报告的 8BF 变体。8BF 复用了部分组件,但其第三步为 `report-only`,不属于常规三步会商主路径。
## 2. 公共机制
### 2.1 会商记录与保存
功能:
- 保存任务意图、研讨过程、会商结论、第三步报告及当前已完成步骤。
- 支持新建会商、历史记录切换、重命名、删除和从已有记录继续。
- 普通入口按当前用户隔离;任务深链按任务共享,进入同一任务的用户看到同一批会商和后台任务。
- 更新使用乐观锁;版本不一致时后端返回 `409`,前端应以服务端最新记录为准后再处理。
接口:
| 场景 | 接口 | 调用方式与参数 |
| --- | --- | --- |
| 普通会商列表 | `GET /api/roundtable-drafts` | 无请求体,按当前用户返回。 |
| 新建普通会商 | `POST /api/roundtable-drafts` | JSON:`{ id?, title, furthest_step, step1, step2, step3 }`。 |
| 读取/更新/删除普通会商 | `GET/PUT/DELETE /api/roundtable-drafts/{draftId}` | `PUT` 传需更新字段及 `expected_version`。 |
| 任务会商列表 | `GET /api/roundtable-task-drafts/by-task/{taskId}` | `taskId` 为任务 ID。 |
| 读取最新任务会商 | `GET /api/roundtable-task-drafts/by-task/{taskId}/latest` | 用于任务进入后恢复最近一次会商。 |
| 新建任务会商 | `POST /api/roundtable-task-drafts` | JSON:`{ id?, task_id, title, furthest_step, step1, step2, step3 }`。 |
| 读取/更新/删除任务会商 | `GET/PUT/DELETE /api/roundtable-task-drafts/{draftId}` | `PUT` 为局部更新并携带 `expected_version`。 |
参数说明:
- `step1`、`step2`、`step3` 保存的是各步骤可恢复的完整页面状态,而不是单一文本。
- `furthest_step` 记录用户历史上到达的最远步骤,用于恢复导航可用性。
- `xdfx-A` 的页面记录和后台任务分区使用 URL 原始行动 ID;任务正文及任务详情仍使用解析后的实际任务 ID。
### 2.2 流式调用与附件
功能:
- 大模型回复、意图澄清、推荐、研讨、报告和流程图均通过 SSE 增量返回。
- 用户可停止当前流;前端按事件逐段追加正文、思考、工具调用、澄清卡片和错误信息。
- 有文件时先上传到对应线程,再将后端返回的虚拟路径传给后续流式接口。
附件接口:
```http
POST /api/threads/{threadId}/uploads
Content-Type: multipart/form-data
files: <file> # 可重复,支持多文件
```
响应中的 `{ filename, size, virtual_path }` 应转换后传入流式请求:
```json
{
"files": [
{
"filename": "任务材料.docx",
"size": 10240,
"path": "/mnt/user-data/uploads/任务材料.docx",
"status": "uploaded"
}
]
}
```
所有 JSON 接口经前端 `apiFetch` 调用,自动携带当前登录态;流式接口使用 `ReadableStream` 解析 SSE。
---
# 第一步:任务意图理解
## 1. 功能
第一步将用户的自然语言任务转成可供多个智能体研讨的结构化意图,并确定后续参会智能体来源。
- 创建内置「任务意图理解」智能体会话,接收任务描述、补充材料和多轮追问。
- 流式展示智能体回复、思考过程和工具型澄清问题。
- 澄清卡支持单选、多选、自定义填写、跳过和继续追问;同一轮可返回多张澄清卡。
- 意图完成后生成可编辑的结构化摘要:目标(`objective`)、约束(`constraints`)、可选假设(`assumptions`)。
- 支持手工修改意图摘要后再进入下一步。
- 智能体选择有两条路径:
- **智能体推荐**:依据意图,在可用智能体候选池中推荐参会人及理由。
- **业务链条**:选择已配置的业务链条,带入席位、阶段、阶段目标、协调人提示词和席位模型策略。
- 任务深链模式自动加载任务卡片、预填任务上下文并自动选择业务链;普通模式在“选择参会智能体”弹窗中手工选择“我的”或“公共”业务链。
步骤流转:
```text
输入任务 / 上传材料
↓
意图智能体澄清(可多轮)
↓
结构化意图完成并可编辑
↓
智能体推荐 或 选择业务链
↓
进入第二步
```
### 1.1 业务链功能与两个弹窗
业务链是可命名、可复用、可保存的“智能体编排模板”,不是单纯的智能体名单。一条链定义了谁参会、谁先后执行、哪些席位并行、每阶段应产出什么,以及协调人如何派发和汇总。
第一步中有两个职责不同的业务链入口:
| 入口 | 弹窗/页面 | 作用 | 是否直接开始研讨 |
| --- | --- | --- | --- |
| 页面顶栏“业务链条” | BusinessChainListDialog | 浏览、筛选、启停、发布、进入配置页编辑业务链。 | 否,它是管理入口。 |
| 意图完成后点击“选择参会智能体 / 进入研讨” | RecommendAgentsDialog 的“业务链条”页签,内部为 BusinessChainPicker | 从可用链中选择一条,校验席位后把编排结果带入第二步。 | 是,确认“进入研讨”后开始第二步。 |
#### A. 选择参会智能体弹窗中的“业务链条”页签
功能:
- 弹窗有“智能体推荐”和“业务链条”两个页签;切换到业务链条后不会调用推荐模型,而是读取已保存的链条。
- 可在“我的 / 公共”之间筛选:
- **我的**:当前用户创建的业务链。
- **公共**:已发布、所有账号都可查看和选用的业务链。
- 每张链条卡展示链条名称、描述、席位数和席位编排流:
- 线性链用“智能体 A → 智能体 B → 智能体 C”表示顺序。
- 同一阶段有多个席位时显示“并行 N”分组;阶段之间仍用箭头表示串行依赖。
- 实时智能体名称优先于链条保存时的名称快照;已删除智能体会置灰并提示。
- 仅启用的链条可进入选择列表;选中链条后,至少保留 **2 个仍存在的可用席位** 才能点击“进入研讨”。
- 如果链条配置了默认执行模式,弹窗顶部的执行模式会自动带入该值,用户仍可临时改为:
- flash:快速,不开启思考。
- thinking:思考,低推理强度。
- pro:专业问答,思考 + 中等推理强度。
- ultra:多智能体问答,思考 + 高推理强度,并允许席位调用子代理。
- 如果链条含有有效分层、阶段目标或协调人提示词,选择后按 dag 编排;否则按 chain 线性编排。
- DAG 链在弹窗底部额外选择执行方式:
- **快速 · 双列禁写**:同阶段席位并行,主区双列展示,并行席位不写文件。
- **沙箱 · 单列可写**:同阶段仍并行,但主区单列展示,允许文件产出,右侧沙箱随当前席位切换。
- “配置链条”按钮跳转到业务链编辑页;没有链条时也会显示“去配置业务链条”引导。
确认后传给第二步的运行结果可概括为:
~~~json
{
"agents": [
{
"agent_id": "agent-001",
"name": "态势专家",
"model": "该席位模型覆盖,可为空",
"seat_skill_directive": true,
"human_validation": false,
"seatMode": "该席位推理深度覆盖,可为空"
}
],
"mode": "chain | dag",
"chain": {
"id": "chain-id",
"title": "任务综合研判链"
},
"plan": {
"stages": "仅 dag 时携带的分层执行计划"
},
"dagExecMode": "fast | sandbox",
"seatMode": "本次会商的链条级执行模式",
"gatherFirst": true
}
~~~
其中,席位数组的顺序就是线性链执行顺序;DAG 时按阶段展平。单席位的 seatMode、模型覆盖、技能识别强化和人工校验会一并继承到第二步。
#### B. 顶部“业务链条”管理弹窗
功能:
- 顶栏点击“业务链条”打开,定位为“浏览和管理”,不直接选择参会人。
- 支持按 **我的 / 公共 / 全部(仅管理员)** 筛选,再按 **全部状态 / 启用 / 停用** 过滤。
- 每张卡片展示:
- 名称、描述、席位数量;
- 公共、待审核、已停用等状态;
- 配置人和最后修改时间;
- 智能体编排流:同 Stage 的席位用“并行 N”分组,Stage 之间以箭头连接。
- 本人链条或管理员可在卡片上:
- 启用 / 停用;
- 发布为公共、取消发布;
- 草稿链提交审核,审核中可撤回;
- 点击“设置”跳转到该链条的编辑页。
- 新建和编辑页面包含:
- **基本信息**:标题、描述、默认执行模式、研讨前并行取数开关、总控提示词。
- **链条编排**:从候选智能体池拖拽到 Stage;可新建、删除、上下移动 Stage,移动/拆分/合并席位。
- **阶段目标**:每个 Stage 可填写目标,并可使用 AI 优化;阶段目标会指导协调人该阶段产出什么、如何承接前一阶段结果。
- **总控提示词**:说明协调人如何派发、汇总、收口,支持 Markdown 和 AI 优化。
- **席位级配置**:模型覆盖、推理深度覆盖、会商技能识别强化、人工校验;岗位协同专用入口还可配置岗位归属和产物位置。
- **编排预览**:以流程图检查“同层并行、层间串行”的最终结构。
两个业务链弹窗的页面结构:
~~~text
顶部“业务链条”管理弹窗
┌ 标题和说明 ───────────────────────────────────────────────────────────┐
│ 筛选:我的 / 公共 / 全部(管理员) | 全部状态 / 启用 / 停用 │
├ 业务链卡片列表 ───────────────────────────────────────────────────────┤
│ 名称、席位数、公共/待审核/停用状态、配置人、更新时间、说明 │
│ 智能体 A → [并行:智能体 B、智能体 C] → 智能体 D │
│ 操作:启停 / 发布或撤回 / 设置 │
├───────────────────────────────────────────────────────────────────────┤
│ 底部:配置(新建或跳转到业务链编辑页) │
└───────────────────────────────────────────────────────────────────────┘
“选择参会智能体”弹窗的业务链页签
┌ 顶部:智能体推荐 | 业务链条 | 本次执行模式(快速/思考/专业/多智能体)┐
│ 筛选:我的 / 公共 │
├ 链条选择卡片 ─────────────────────────────────────────────────────────┤
│ 名称、描述、席位数、线性/分层编排、已删除席位告警 │
├───────────────────────────────────────────────────────────────────────┤
│ DAG 链:快速·双列禁写 | 沙箱·单列可写 │
│ 底部:配置链条 | 取消 | 进入研讨 │
└───────────────────────────────────────────────────────────────────────┘
~~~
## 2. 接口、调用时机与传参
### 2.1 初始化意图会话
```http
POST /api/intent/init
Content-Type: application/json
```
```json
{
"model": "模型标识,可选,使用页面当前模型",
"task_context": {
"task_id": "任务深链时的任务 ID",
"task_name": "任务名称",
"task_goal": "任务目标",
"business_code": "3Q | 6BF | 7BF"
},
"intent_agent_id": "roundtable-intent"
}
```
说明:
- 普通会商一般省略 `task_context`,`intent_agent_id` 也可省略并由后端使用内置 `roundtable-intent`。
- 返回 `{ status, agent_id, thread_id }`;后续上传与流式对话都使用此 `thread_id`。
### 2.2 发送任务或回答澄清问题
```http
POST /api/intent/stream
Accept: text/event-stream
```
```json
{
"thread_id": "意图会话线程 ID",
"message": "用户任务描述,或对澄清问题的答案",
"model": "页面当前模型,可选",
"intent_agent_id": "roundtable-intent",
"task_context": {
"task_id": "任务 ID",
"task_name": "任务名称",
"task_goal": "任务目标",
"business_code": "业务编码"
},
"client_turn_id": "前端生成的幂等 ID",
"files": [
{
"filename": "材料.pdf",
"size": 10240,
"path": "/mnt/user-data/uploads/材料.pdf",
"status": "uploaded"
}
]
}
```
主要 SSE 完成帧字段:
```json
{
"status": "asking | clarification | done | error",
"content": "本轮可见回答",
"summary": {
"objective": "任务目标",
"constraints": ["约束 1"],
"assumptions": ["可选假设"]
},
"question": "单个澄清问题",
"clarifications": ["多个澄清问题"],
"clarification_type": "single | multiple | text",
"clarification_context": {},
"options": ["选项 A", "选项 B"],
"allow_custom": true,
"allow_multiple": false,
"error_detail": "失败原因"
}
```
调用要点:
- `client_turn_id` 用于避免重试或网络抖动造成同一用户轮次重复执行。
- 用户选项、填写的自定义答案、点击“继续/跳过”后,仍通过本接口的 `message` 继续同一 `thread_id`。
- 上传接口必须先于本接口调用;流式接口只传上传成功后的虚拟路径。
### 2.3 获取候选智能体和执行推荐
```http
GET /api/agents
```
前端从返回列表中排除内置工具型智能体,将可参会的候选人整理成:
```json
{
"agent_id": "agent-001",
"name": "态势研判专家",
"description": "负责态势信息研判"
}
```
```http
POST /api/recommend/stream
Accept: text/event-stream
```
```json
{
"intent": {
"objective": "形成处置建议",
"constraints": ["时限 24 小时"],
"assumptions": ["数据可访问"]
},
"candidates": [
{
"agent_id": "agent-001",
"name": "态势研判专家",
"description": "负责态势信息研判"
}
],
"model": "页面当前模型"
}
```
推荐完成帧可得到:
```json
{
"status": "done",
"content": "推荐过程说明",
"picks": [
{
"agent_id": "agent-001",
"reason": "与任务目标的匹配理由"
}
]
}
```
普通会商会额外保存推荐记录,便于恢复和审计:
| 接口 | 参数 |
| --- | --- |
| `GET /api/roundtable-drafts/{draftId}/recommendations` | 无请求体,读取该草稿的推荐历史。 |
| `POST /api/roundtable-drafts/{draftId}/recommendations` | `{ objective, status, model?, rationale?, picks, candidates }`。 |
### 2.4 读取、选择和管理业务链
| 接口 | 调用方式与参数 |
| --- | --- |
| `GET /api/roundtable-chains?scope=public\|mine\|pending\|all` | 获取业务链列表;入口页通常读取公开链。 |
| `GET /api/roundtable-chains/{id}` | 获取某条业务链完整定义。 |
| `POST /api/roundtable-chains` | 新建业务链。 |
| `PUT /api/roundtable-chains/{id}` | 更新业务链。 |
| `DELETE /api/roundtable-chains/{id}` | 删除业务链。 |
| `POST /api/roundtable-chains/optimize-prompt` | 使用模型优化总控提示词或阶段目标。 |
读取与弹窗行为:
- “选择参会智能体”弹窗调用 GET /api/roundtable-chains(我的)或 GET /api/roundtable-chains?scope=public(公共),并同时调用 GET /api/agents 校验每个席位是否仍存在。
- 顶部管理弹窗在管理员身份下还可调用 scope=all;scope=pending 用于待审核链的管理场景。非管理员请求 all/pending 时后端会退化为当前用户范围。
- 启用状态为 false 的链条仍可在管理弹窗查看,但不会出现在“选择参会智能体”弹窗中。
创建或更新业务链的核心参数示例:
```json
{
"title": "任务综合研判链",
"description": "先收集信息,再由专家研讨",
"seats": [
{
"agent_id": "agent-001",
"name": "态势专家",
"description": "分析外部态势",
"model": "模型标识",
"seat_skill_directive": true,
"human_validation": true,
"seat_mode": "flash"
}
],
"stages": [["agent-001", "agent-002"], ["agent-003"]],
"stage_goals": ["平行收集信息", "汇总形成判断"],
"coordinator_prompt": "协调人需要按风险、机会、建议汇总",
"seat_mode": "flash",
"gather_first": true
}
```
其中:
- 链条创建时前端使用驼峰字段 stageGoals、coordinatorPrompt、seatMode、gatherFirst;请求发送前映射为接口字段 stage_goals、coordinator_prompt、seat_mode、gather_first。更新时传 null 可清除分层、阶段目标、总控提示词或默认执行模式。
- `stages` 表示 DAG 分层:同层可并行,不同层按顺序执行。
- `seat_mode` / 席位 `seat_mode` 可取 `flash`、`thinking`、`pro`、`ultra`。
- model 为空时,该席位跟随第二步页面的全局模型;有值时仅覆盖该席位。
- seat_skill_directive: true 会在该席位运行时强化其技能识别和使用指令;它与智能体自身同名开关任一开启即可生效。
- `human_validation: true` 表示该席位输出后需要人工确认才可继续。
- `gather_first: true` 表示先让全部席位平行收集信息,再进入正式研讨。
发布、审核和启停均通过更新接口发送局部字段:
| 操作 | PUT /api/roundtable-chains/{id} 请求体 |
| --- | --- |
| 启用 / 停用 | { "enabled": true } / { "enabled": false } |
| 直接发布 / 取消发布 | { "is_public": true } / { "is_public": false } |
| 提交审核 / 撤回审核 | { "pending_review": true } / { "pending_review": false } |
| 管理员审核发布 | { "is_public": true, "pending_review": false } |
提示词优化接口的请求示例:
~~~json
{
"prompt_text": "当前总控提示词或阶段目标原文",
"kind": "coordinator | stage_goal",
"context": "链条标题、各阶段席位及已有阶段目标组成的上下文",
"model_name": "可选模型标识"
}
~~~
返回:
~~~json
{
"optimized": "可直接回填到总控提示词或阶段目标编辑框的文本"
}
~~~
## 3. 页面结构
```text
┌──────────────────────────────── 页面顶部 ────────────────────────────────┐
│ 三步导航:①任务意图理解 ②多智能体研讨 ③方案结果展示 │
│ 业务链 / 新建或重新分析 / 保存草稿 / 历史记录 / 模型选择 / 设置 │
└───────────────────────────────────────────────────────────────────────┘
┌──────────── 左侧入口栏 ───────────┬──────────── 中间工作区 ────────────┬──── 右侧摘要栏 ────┐
│ 任务卡(仅任务深链) │ Step1 对话面板 │ 当前模型选择 │
│ 业务链列表与展开关系 │ - 意图智能体消息 │ 结构化意图摘要 │
│ 会商/分析历史记录 │ - 思考、工具、澄清卡 │ - 目标 │
│ │ - 输入框、附件、发送/停止/继续 │ - 约束 │
│ │ │ - 假设,均可编辑 │
└───────────────────────────────────┴────────────────────────────────────┴────────────────────┘
```
任务深链还会显示任务目的入口和底部 `TaskJumpBar` 快捷跳转栏;任务模式隐藏手工选择业务链的入口,以深链业务编码自动选择链条。
---
# 第二步:多智能体研讨
## 1. 功能
第二步以第一步意图和选定智能体/业务链为输入,创建协调人与多个席位智能体,进行可观察、可干预、可恢复的会商。
- 为每位参会智能体和协调人创建独立线程。
- 支持三种编排模式:
- **推荐模式(recommend)**:协调人自由决定调度哪些推荐智能体。
- **链条模式(chain)**:按业务链指定的席位顺序执行。
- **DAG 模式(dag)**:同阶段并行、跨阶段串行;可传入阶段目标和协调人提示词。
- DAG 支持 `fast` 与 `sandbox` 执行视图。快速模式会限制并行席位写文件;沙箱模式可产出和预览文件。
- 可选“先收集后研讨”:全部席位先并行收集资料,再将有效交付共享给正式研讨。
- 协调人可继续派发、发起人工澄清,或在不再派发时形成共识。
- 用户可暂停/继续本地编排,回答协调人的澄清问题,向协调人追加文字或附件。
- 席位可配置人工验证点;达到验证点后需人工确认。
- 支持打开角色画像抽屉,在下一次运行前调整单席位模型和运行策略。
- 实时展示角色状态、对话、思考、工具调用、阶段流图、并行席位、文件产物和人工参与记录。
- 每次重新推荐或选择链条都会创建独立“研讨运行快照”;历史运行互不覆盖,可在左侧切换查看。
- 支持将长时间会商转入后台任务。后台任务可被同一任务的其他用户看到、跟踪、继续回答或接管。
步骤门槛:
- 只有第一步的 `intentReady` 为真时,第二步可进入。
- 协调人形成共识(`hasConsensus`)后,第三步才可进入。
## 2. 接口、调用时机与传参
### 2.1 初始化所有参会线程
```http
POST /api/multi-agent/init
Accept: text/event-stream
```
```json
{
"agent_names": ["agent-001", "agent-002"],
"main_agent_name": "coordinator",
"model": "页面当前模型,可选"
}
```
说明:
- `agent_names` 为选中的席位智能体标识。
- `main_agent_name` 为协调人标识。
- SSE 依次返回席位就绪、协调人就绪和初始化完成事件,最终得到线程映射:
```json
{
"thread_ids": {
"agent-001": "席位线程 ID",
"agent-002": "席位线程 ID",
"coordinator": "协调人线程 ID"
}
}
```
### 2.2 驱动协调人和席位研讨
```http
POST /api/multi-agent/run/stream
Accept: text/event-stream
```
基础请求:
```json
{
"agent_type": "leader | special",
"agent_name": "coordinator 或席位 agent ID",
"display_name": "页面展示名称",
"d_agent_thread_id": {
"coordinator": "协调人线程 ID",
"agent-001": "席位线程 ID"
},
"new_message": "给协调人或席位的本轮提示词",
"model": "模型标识",
"business_code": "3Q | 6BF | 7BF",
"files": []
}
```
关键参数:
| 参数 | 适用对象 | 用途 |
| --- | --- | --- |
| `agent_type: "leader"` | 协调人 | 由协调人分析现状、派发席位或形成共识。 |
| `agent_type: "special"` | 席位、总结/报告等专用智能体 | 执行专业分析、总结或文件生成。 |
| `d_agent_thread_id` | 全部 | 是“智能体 ID → 线程 ID”的映射,不是单一线程 ID。 |
| `thinking_enabled?` | 席位 | 是否启用思考。 |
| `reasoning_effort?` | 席位 | 推理强度。 |
| `subagent_enabled?` | 席位 | 是否允许席位再调用子智能体。 |
| `seat_skill_directive?` | 席位 | 席位特定的技能使用指令。 |
| `parallel_no_file?` | 并行席位 | 快速并行时限制文件写入。 |
| `peer_deliveries?` | 后续席位/协调人 | 传递前序席位可见交付物。 |
| `synthesis_mode?` | 协调人 | 指示汇总类执行。 |
| `suppress_pre_broadcast?` | 协调人 | 控制汇总前广播。 |
| `skill_stop_names?` | 全部 | 指定需要拦截/停止的技能名称。 |
流式完成后前端重点读取:
```json
{
"dispatched": ["agent-001"],
"content": "可见回答或结论",
"agentName": "本次完成者",
"modelUsed": "实际使用模型",
"clarification": {
"question": "需要用户回答的问题",
"options": ["选项 A"]
},
"invalidDelivery": false
}
```
编排规则:
- 协调人先运行并决定需调度的席位。
- 每个席位完成后,将其“可见回答”作为交付物回传,思考内容不作为席位交付。
- 链条模式按链定义的顺序运行;DAG 模式同层并行、阶段间串行。
- 协调人返回不再派发且无待答澄清时,前端将结果标记为共识。
### 2.3 产物查看与下载
| 接口 | 调用方式 |
| --- | --- |
| `GET /api/threads/{threadId}/artifacts` | 查询指定协调人或席位线程的文件产物。 |
| `GET /api/threads/{threadId}/artifacts/{path}` | 预览或下载文件;下载时前端附加 `?download=true`。 |
### 2.4 后台会商任务
开始后台任务:
```http
POST /api/roundtable-jobs
Content-Type: application/json
```
```json
{
"requestId": "前端请求 ID",
"draftId": "会商草稿 ID",
"taskId": "任务深链时的任务 ID",
"intent": {
"objective": "任务目标",
"constraints": ["约束"],
"assumptions": ["假设"]
},
"agents": [
{
"agentId": "agent-001",
"name": "态势专家"
}
],
"model": "当前模型",
"orchestrationMode": "recommend | chain | dag",
"chain": {
"id": "chain-id",
"title": "业务链名称"
},
"orchestrationPlan": {},
"seedMessage": "首次给协调人的提示",
"threadIds": {
"coordinator": "线程 ID",
"agent-001": "线程 ID"
},
"coordinatorName": "协调人名称",
"seat_skill_directives": {
"agent-001": true
},
"seat_modes": {
"agent-001": "thinking"
},
"gather_first": true,
"business_code": "3Q",
"thinking_enabled": true,
"reasoning_effort": "medium",
"subagent_enabled": false
}
```
后台任务接口:
| 接口 | 调用方式与参数 |
| --- | --- |
| `GET /api/roundtable-jobs?draft_id={draftId}&task_id={taskId}` | 获取草稿/任务关联的后台任务列表。任务模式需带 `task_id`。 |
| `GET /api/roundtable-jobs/{jobId}?task_id={taskId}` | 获取任务快照。 |
| `GET /api/roundtable-jobs/{jobId}/stream?task_id={taskId}` | SSE 跟踪后台任务完整进度。 |
| `POST /api/roundtable-jobs/{jobId}/resume?task_id={taskId}` | JSON:`{ answer }`,用于回答后台任务等待的人工问题。 |
| `POST /api/roundtable-jobs/{jobId}/cancel?task_id={taskId}` | 取消后台任务;前台接管时也会先结束后台执行。 |
状态和阶段:
| 分类 | 枚举 |
| --- | --- |
| 任务状态 | `queued`、`running`、`awaiting_input`、`done`、`error`、`cancelled` |
| 执行阶段 | `initializing`、`leader_thinking`、`dispatching`、`consensus`、`summary_writing`、`report_drawing`、`report_done` |
## 3. 页面结构
```text
┌──────────────────────────────── 页面顶部 ────────────────────────────────┐
│ 三步导航 / 会商记录 / 模型选择 │
└───────────────────────────────────────────────────────────────────────┘
┌──────────── 可收起左栏 ───────────┬──────────── 中间研讨区 ─────────────┬──── 右侧沙箱区 ────┐
│ 意图摘要 │ 顶部:模型、暂停/继续、转后台 │ Step2SandboxLayout │
│ 角色列表与席位筛选 │ DAG 流程缩略图、并行席位切换 │ 文件/网页预览 │
│ 人工参与/验证状态 │ 对话时间线:协调人、席位、工具、思考 │ 产物查看和下载 │
│ 多次研讨运行快照切换 │ 澄清问题卡、人工确认卡 │ 打开时左栏自动收起 │
│ 任务概览(任务深链) │ 底部:追加消息、附件、发送 │ │
└───────────────────────────────────┴─────────────────────────────────────┴────────────────────┘
```
页面展示规则:
- 角色卡显示席位状态、当前轮次、模型和是否等待人工确认。
- 对话区可按角色筛选,思考内容默认折叠,工具调用和交付物以步骤卡展示。
- DAG 研讨可打开流程面板观察阶段、依赖和并行关系。
- 打开沙箱/产物预览后,优先保证产物可读区域,左侧栏自动收起。
---
# 第三步:方案结果展示
## 1. 功能
第三步基于第一步意图、第二步席位交付和协调人共识,生成可阅读、可修改、可下载、可继续加工的最终方案。
- 首次进入常规会商第三步时,启动三个相互独立的产出流:
- **方案总结报告**:生成 Markdown 方案,是默认主界面。
- **经典可视化报告**:生成 HTML 风格报告/仪表盘。
- **结构化仪表盘**:生成 `report-json`,由前端 `DashboardApp` 渲染。
- 三条流以约 0 / 300 / 600 ms 错峰启动,减少瞬间请求峰值,但互不等待。
- 已保存草稿再次打开时优先恢复既有结果,不重复生成;切换到新会商运行时会终止旧运行的活跃流。
- Markdown 报告完成后,常规模式自动调用流程图提取,生成 `flow-json` 结构化流程图。
- 用户可对报告提问、要求重写、修改流程图、重新生成流程图或报告。
- 任务深链可根据业务链层次和业务编码生成任务 → 目的 → 行为体等结构;行动业务会使用行动名称作为根节点。
- 若任务和技能条件满足,可选择“现在导入 / 稍后导入 / 不再导入”,把报告和流程结构交给 `roundtable-structure` 进行任务结构化入库。
- 左侧汇集协调人共识、各席位交付和文件;右侧可预览 Markdown、流程图及沙箱产物。
- 支持下载会商文档和智能体产物。任务模式还可将选定产物提交到任务交付接口。
## 2. 接口、调用时机与传参
### 2.1 初始化第三步专用智能体
| 目标 | 接口 | 返回 |
| --- | --- | --- |
| Markdown 方案总结 | `POST /api/multi-agent/summary/init` | `{ agent_name, thread_id }` |
| 经典可视化报告 | `POST /api/multi-agent/report/init` | `{ agent_name, thread_id }` |
| 结构化仪表盘 | `POST /api/multi-agent/dashboard/init` | `{ agent_name, thread_id }` |
| 任务结构化入库 | `POST /api/multi-agent/structure/init` | `{ agent_name, thread_id }` |
初始化请求体均为:
```json
{}
```
各专用智能体初始化后,均继续通过统一接口 `POST /api/multi-agent/run/stream` 运行。
### 2.2 生成或修改 Markdown 方案总结
```json
{
"agent_type": "special",
"agent_name": "roundtable-summary",
"display_name": "方案总结报告",
"d_agent_thread_id": {
"roundtable-summary": "总结线程 ID"
},
"new_message": "包含结构化意图、席位交付、协调人共识、链条提示词的生成或修改指令",
"model": "当前模型",
"business_code": "3Q",
"files": []
}
```
功能覆盖:
- 首次生成 Markdown 报告。
- 在报告下方继续问答或下达修改指令。
- 支持暂停、继续、重新生成和生成后下载 Docx。
- 上述问答与修改沿用同一总结线程,保证上下文连续。
### 2.3 生成经典报告和仪表盘
经典报告请求使用 `roundtable-report`:
```json
{
"agent_type": "special",
"agent_name": "roundtable-report",
"d_agent_thread_id": {
"roundtable-report": "报告线程 ID"
},
"new_message": "包含意图、席位交付、共识、主题模式、修订要求和已有 HTML 的提示词",
"model": "当前模型"
}
```
结构化仪表盘请求使用 `roundtable-dashboard`:
```json
{
"agent_type": "special",
"agent_name": "roundtable-dashboard",
"d_agent_thread_id": {
"roundtable-dashboard": "仪表盘线程 ID"
},
"new_message": "包含意图、席位交付、共识,或对已有仪表盘的修订要求",
"model": "当前模型"
}
```
前端依据返回的 HTML 或 `report-json` 分别渲染经典报告和 `DashboardApp`,并提供全屏、在新窗口打开、继续优化以及切回经典报告的操作。
### 2.4 自动提取和修改流程图
```http
POST /api/flow-extract/stream
Accept: text/event-stream
```
```json
{
"report_md": "Markdown 完整报告",
"seat_deliveries": [
{
"sender": "态势专家",
"content": "席位可见交付"
}
],
"chain_levels": [["信息收集"], ["研判决策"]],
"coordinator_prompt": "协调人对结构层次的要求",
"business_code": "3Q",
"root_label": "任务根节点名称",
"model": "当前模型",
"current_graph": {
"nodes": [],
"edges": []
},
"instruction": "用户对当前流程图的修改要求"
}
```
参数使用规则:
- 首次自动提取可不传 `current_graph` 和 `instruction`。
- 修改现有图时传当前图和用户要求。
- 任务模式的 `chain_levels` 由业务链阶段目标推导;若 `coordinator_prompt` 明确规定层次,则优先使用该要求。
流中包含提取增量、校验过程、模型切换和最终图数据,最终形成前端 `FlowGraphPanel` 使用的 `flow-json`。
### 2.5 判断用户在第三步的意图
| 接口 | 请求体 | 返回用途 |
| --- | --- | --- |
| `POST /api/flow-extract/intent` | `{ message, has_report, has_flow, can_ingest, model? }` | 分类为 `regenerate_report`、`modify_flow`、`regenerate_flow`、`ingest`、`qa`、`unclear`,决定继续调用哪一条流。 |
| `POST /api/flow-extract/ingest-intent` | `{ message, model? }` | 在已提示导入或稍后导入时,判断 `start_ingest`、`add_data`、`other`、`unclear`。 |
### 2.6 任务结构化入库
先检查是否可入库:
```http
POST /api/flow-extract/ingest-eligibility
```
```json
{
"task_id": "任务 ID",
"business_code": "3Q",
"chain_name": "业务链名称",
"coordinator_prompt": "协调人提示词",
"report_title": "报告标题",
"model": "当前模型"
}
```
返回:
```json
{
"can_ingest": true,
"skill": "命中的入库技能",
"reason": "是否可入库的原因"
}
```
符合条件且用户确认后,初始化 `roundtable-structure` 线程,并调用统一研讨流:
```json
{
"agent_type": "special",
"agent_name": "roundtable-structure",
"d_agent_thread_id": {
"roundtable-structure": "结构化入库线程 ID"
},
"new_message": "包含 taskId、业务编码/链条/技能提示、最新 Markdown 报告、flow-json 和用户补充说明的指令",
"model": "当前模型",
"business_code": "3Q"
}
```
注意:前端不会直接调用某个入库技能,而是交给 `roundtable-structure` 智能体在具备完整报告和流程图上下文后执行。
### 2.7 任务交付物提交
任务深链启用交付配置时,第三步可以查询和更新任务产物提交状态。
| 接口 | 调用方式与参数 |
| --- | --- |
| `GET /api/roundtable/tasks/{taskId}/artifacts?submitted=true\|false` | 获取任务已提交或待提交产物。 |
| `PUT /api/roundtable/tasks/{taskId}/artifacts/submission` | 更新某个产物的提交状态。 |
```json
{
"taskId": "任务 ID",
"submitted": true,
"registerOnly": false,
"submissionId": "已有提交记录 ID,可选",
"taskDeliveryId": "外部交付 ID,可选",
"expectedVersion": 3,
"artifact": {
"sessionId": "会商会话 ID",
"threadId": "产物所属线程 ID",
"nodeKey": "流程节点标识,可选",
"sourceKey": "来源标识",
"path": "/mnt/user-data/outputs/report.md",
"name": "会商报告.md",
"mimeType": "text/markdown",
"revision": 1
}
}
```
## 3. 页面结构
默认的“方案总结”视图:
```text
┌──────────────────────────────── 页面顶部 ────────────────────────────────┐
│ 步骤导航 / 报告标题 / 模型 / 总结报告、流程图、最终方案等视图切换 │
└───────────────────────────────────────────────────────────────────────┘
┌──────────── 可收起左栏 ───────────┬──────────── 中间主内容 ─────────────┬──── 右侧结果区 ────┐
│ 协调人共识 │ Markdown 总结报告对话流 │ Markdown 预览 │
│ 各席位交付 │ 报告问答、修改、重生成入口 │ 或 FlowGraphPanel │
│ 各线程文件/产物 │ 输入框与附件 │ 文件/沙箱预览 │
│ │ │ │
└───────────────────────────────────┴─────────────────────────────────────┴────────────────────┘
```
其他结果视图:
| 视图 | 中央区域 | 右侧/扩展区域 |
| --- | --- | --- |
| 最终方案 | 汇总后的静态方案和文件清单 | 可查看来源与下载产物。 |
| 经典可视化报告 | 报告生成对话、修订指令 | HTML/沙箱预览,支持全屏和下载。 |
| 结构化仪表盘 | 仪表盘优化对话 | `DashboardApp` 或 HTML 视图,可新窗口打开。 |
| 流程图 | 报告问答和流程图修改指令 | `FlowGraphPanel` 显示节点、关系和层级。 |
常规第三步会隐藏外层研讨左导航,以扩大结果阅读区域;任务深链保留任务环境相关的交付与跳转能力。
## 4. 三步数据衔接
```text
第一步
结构化意图 + 已选智能体/业务链 + 意图线程
│
▼
第二步
席位线程 + 协调人线程 + 对话/交付 + 共识 + 研讨运行快照
│
▼
第三步
Markdown 报告 + HTML 报告 + report-json 仪表盘 + flow-json 流程图 + 任务入库/交付
```
关键约束:
- 第一步未形成有效意图,不能开始第二步。
- 第二步未形成协调人共识,不能进入第三步。
- 第三步的所有产出都应绑定对应的第二步研讨运行快照,避免新一轮会商覆盖历史结果。
- 后端发生模型降级/切换时,前端应保留已收到的流内容并显示实际使用模型或切换提示。
## 5. 主要前端模块索引
| 范围 | 主要文件/目录 |
| --- | --- |
| 页面编排 | `src/roundtable-planning/pages/RoundtablePlanningPage.tsx` |
| 第一步 | `components/Step1Panel.tsx`、`hooks/useStep1Intent.ts`、`api/intent.ts` |
| 推荐与业务链 | `api/recommend.ts`、`components/RecommendAgentsDialog.tsx`、`api/chains.ts` |
| 第二步 | `components/Step2Panel.tsx`、`components/Step2SandboxLayout.tsx`、`hooks/useStep2Orchestration.ts` |
| 多智能体与后台任务 API | `api/multi-agent.ts`、`api/roundtable-jobs.ts` |
| 第三步 | `components/Step3Panel.tsx`、`components/HighFidelityReport.tsx`、`hooks/useStep3Summary.ts`、`hooks/useStep3Report.ts`、`hooks/useStep3Dashboard.ts` |
| 流程图与任务入库 | `api/flow-extract.ts`、`api/ingest.ts` |
| 草稿持久化 | `api/drafts.ts`、`api/task-drafts.ts`、相关草稿 hooks |
+5 -67
View File
@@ -12,74 +12,12 @@
root.classList.add("dark");
} catch (e) {}
})();
// Chrome 102 has no AbortSignal.timeout (Chrome 103+). Install before
// any module so LangGraph SDK control requests can set a deadline.
(function () {
try {
if (typeof AbortSignal === "undefined" || typeof AbortSignal.timeout === "function") {
return;
}
AbortSignal.timeout = function (milliseconds) {
var controller = new AbortController();
var timer = setTimeout(function () {
var reason;
try {
reason = new DOMException("signal timed out", "TimeoutError");
} catch (err) {
reason = new Error("signal timed out");
reason.name = "TimeoutError";
}
try {
controller.abort(reason);
} catch (err) {
controller.abort();
}
}, milliseconds);
controller.signal.addEventListener(
"abort",
function () {
clearTimeout(timer);
},
{ once: true },
);
return controller.signal;
};
} catch (err) {}
})();
</script>
<script>
// React 19's development profiler uses the User Timing Level 3
// `performance.measure(name, options)` overload. Firefox 101 only
// implements the legacy string-marker form and otherwise throws a
// DOMException during every scheduled update. Detect that overload
// before React loads and disable its optional profiler when unavailable.
(function () {
try {
var perf = window.performance;
if (!perf || typeof perf.measure !== "function" || typeof perf.now !== "function") return;
var probe = "__deerflow_user_timing_options_probe__";
var now = perf.now();
perf.measure(probe, { start: now, end: now });
if (typeof perf.clearMeasures === "function") perf.clearMeasures(probe);
} catch (e) {
try {
Object.defineProperty(window.performance, "measure", {
value: undefined,
configurable: true,
});
} catch (defineError) {
try {
window.performance.measure = undefined;
} catch (assignmentError) {}
}
}
})();
</script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>CM 助手</title>
<script src="/runtime-config.js" data-runtime-config></script>
</head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title>CM 助手</title>
<script src="/runtime-config.js" data-runtime-config></script>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
-5
View File
@@ -12,10 +12,6 @@
"preview": "vite preview",
"typecheck": "tsc --noEmit",
"test:input-mode": "node --experimental-strip-types --test src/components/workspace/input-mode.test.ts",
"test:answer-feedback": "node --experimental-strip-types --test src/components/workspace/agents/agent-feedback-visibility.test.ts src/components/workspace/messages/answer-feedback-eligibility.test.ts src/strategy-components/api/answer-feedback-batching.test.ts",
"test:retrieval-debug": "node --experimental-strip-types --test src/core/llmwiki/retrieval-debug.test.ts",
"test:abort-signal": "node --experimental-strip-types --test src/core/compat/abort-signal.test.ts",
"test:auth-entry": "node scripts/test-auth-entry.mjs",
"test:html-preview": "pnpm exec esbuild src/core/utils/legacy-html-preview.test.ts --bundle --platform=node --format=esm --outfile=.runtime/unit-tests/legacy-html-preview.test.mjs && node --test .runtime/unit-tests/legacy-html-preview.test.mjs",
"test:visualizations": "node --experimental-strip-types --test src/components/workspace/visualizations/visualization-spec.test.ts",
"test:report-collaboration": "npx esbuild src/report-collaboration/tests/event-reducer.test.ts --bundle --platform=node --format=esm --outfile=.runtime/unit-tests/event-reducer.test.mjs && npx esbuild src/report-collaboration/tests/message-adapter.test.ts --bundle --platform=node --format=esm --outfile=.runtime/unit-tests/message-adapter.test.mjs && node --test .runtime/unit-tests/event-reducer.test.mjs .runtime/unit-tests/message-adapter.test.mjs",
@@ -87,7 +83,6 @@
"leaflet": "^1.9.4",
"lucide-react": "^0.562.0",
"maplibre-gl": "^6.9.0",
"marked": "16.4.2",
"mermaid": "^11.15.0",
"motion": "^12.26.2",
"nanoid": "^5.1.6",
@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<defs>
<linearGradient id="ap-add" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f5222d"/>
<stop offset="1" stop-color="#a8071a"/>
</linearGradient>
</defs>
<rect width="52" height="52" rx="8" fill="#ffcfd1"/>
<path fill="url(#ap-add)" d="M26 14a2 2 0 0 1 2 2v8h8a2 2 0 1 1 0 4h-8v8a2 2 0 1 1-4 0v-8h-8a2 2 0 1 1 0-4h8v-8a2 2 0 0 1 2-2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 503 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#ffcfd1;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(2.236 118.236)"><path class="b" d="M9204.336-22218.762a6.4,6.4,0,0,1-2.489-.691,6.242,6.242,0,0,1-2-1.615,6.363,6.363,0,0,1-1.206-2.283,6.357,6.357,0,0,1-.246-1.863c-.047-.033-.094-.066-.139-.1a6.4,6.4,0,0,1-2.272-3.4,6.418,6.418,0,0,1,.268-4.076,6.336,6.336,0,0,1,1.233-1.912,6.383,6.383,0,0,1-.4-1.973,6.41,6.41,0,0,1,.53-2.809,6.441,6.441,0,0,1,1.7-2.289,6.424,6.424,0,0,1,1.751-1.057,4.969,4.969,0,0,1,.343-1.289,4.965,4.965,0,0,1,1.334-1.859,5.038,5.038,0,0,1,2.016-1.082,5.037,5.037,0,0,1,2.289-.074,5.024,5.024,0,0,1,2.089.943,4.947,4.947,0,0,1,.871.861,5.147,5.147,0,0,1,.876-.861,5,5,0,0,1,2.083-.943,5.035,5.035,0,0,1,2.289.074,5.06,5.06,0,0,1,2.021,1.082,5.031,5.031,0,0,1,1.334,1.859,5.008,5.008,0,0,1,.343,1.289,6.424,6.424,0,0,1,1.751,1.057,6.441,6.441,0,0,1,1.7,2.289,6.405,6.405,0,0,1,.524,2.809,6.434,6.434,0,0,1-.4,1.973,6.315,6.315,0,0,1,1.234,1.912,6.418,6.418,0,0,1,.268,4.076,6.4,6.4,0,0,1-2.272,3.4l-.143.105a6.214,6.214,0,0,1-.248,1.859,6.26,6.26,0,0,1-1.2,2.283,6.271,6.271,0,0,1-2.01,1.615,6.354,6.354,0,0,1-2.485.691c-.14.006-.278.012-.418.012a6.213,6.213,0,0,1-2.139-.375,6.394,6.394,0,0,1-2.2-1.34,6.4,6.4,0,0,1-.915-1.066,6.415,6.415,0,0,1-.91,1.066,6.427,6.427,0,0,1-2.206,1.34,6.283,6.283,0,0,1-2.143.377C9204.609-22218.748,9204.473-22218.752,9204.336-22218.762Zm6.768-6.342a4.232,4.232,0,0,0,.346,1.652,4.123,4.123,0,0,0,.972,1.379,4.116,4.116,0,0,0,1.44.877,4.062,4.062,0,0,0,1.67.234,4.159,4.159,0,0,0,1.63-.447,4.159,4.159,0,0,0,1.313-1.061,4.227,4.227,0,0,0,.787-1.49c.02-.07.037-.139.054-.209a6.32,6.32,0,0,1-1.422.164,1.1,1.1,0,0,1-1.1-1.1,1.1,1.1,0,0,1,1.1-1.1,4.178,4.178,0,0,0,2.529-.859,4.138,4.138,0,0,0,1.485-2.221,4.216,4.216,0,0,0-.173-2.67,4.2,4.2,0,0,0-1.765-2.01,1.1,1.1,0,0,1-.4-1.5,1.1,1.1,0,0,1,1.063-.543,4.16,4.16,0,0,0,.1-.758,4.249,4.249,0,0,0-.346-1.838,4.156,4.156,0,0,0-1.117-1.5,4.078,4.078,0,0,0-.569-.408,4.928,4.928,0,0,1-.385.838,1.1,1.1,0,0,1-.955.553,1.08,1.08,0,0,1-.547-.15,1.093,1.093,0,0,1-.4-1.5,2.906,2.906,0,0,0,.374-1.229,1.022,1.022,0,0,1,.006-.145,2.841,2.841,0,0,0-.218-1.133,2.836,2.836,0,0,0-.754-1.051,2.794,2.794,0,0,0-1.139-.607,2.8,2.8,0,0,0-1.29-.045,2.782,2.782,0,0,0-1.173.535,2.84,2.84,0,0,0-.82.994,2.912,2.912,0,0,0-.3,1.262v5.254a4.426,4.426,0,0,0,.877,2.625,4.4,4.4,0,0,0,2.277,1.58,1.1,1.1,0,0,1,.748,1.361,1.1,1.1,0,0,1-1.367.748,6.6,6.6,0,0,1-2.535-1.41v6.928Zm-10.352,1.145a4.119,4.119,0,0,0,.787,1.49,4.148,4.148,0,0,0,1.313,1.061,4.105,4.105,0,0,0,1.624.447,4.076,4.076,0,0,0,1.676-.234,4.125,4.125,0,0,0,1.44-.877,4.208,4.208,0,0,0,.972-1.379,4.226,4.226,0,0,0,.34-1.652v-6.924a6.628,6.628,0,0,1-2.534,1.406,1.117,1.117,0,0,1-.308.045,1.1,1.1,0,0,1-1.055-.793,1.093,1.093,0,0,1,.748-1.361,4.393,4.393,0,0,0,2.272-1.58,4.354,4.354,0,0,0,.876-2.625v-5.254a2.906,2.906,0,0,0-.29-1.262,2.84,2.84,0,0,0-.82-.994,2.778,2.778,0,0,0-1.179-.535,2.8,2.8,0,0,0-1.29.045,2.832,2.832,0,0,0-1.139.607,2.821,2.821,0,0,0-.748,1.051,2.819,2.819,0,0,0-.212,1.271,2.821,2.821,0,0,0,.374,1.234,1.1,1.1,0,0,1-.4,1.5,1.1,1.1,0,0,1-1.5-.4,5.009,5.009,0,0,1-.386-.838,4.127,4.127,0,0,0-.568.408,4.156,4.156,0,0,0-1.117,1.5,4.249,4.249,0,0,0-.346,1.838,4.246,4.246,0,0,0,.1.758,1.106,1.106,0,0,1,1.064.543,1.1,1.1,0,0,1-.4,1.5,4.2,4.2,0,0,0-1.765,2.01,4.216,4.216,0,0,0-.173,2.67,4.138,4.138,0,0,0,1.485,2.221,4.178,4.178,0,0,0,2.529.859,1.1,1.1,0,0,1,1.1,1.1,1.1,1.1,0,0,1-1.1,1.1,6.32,6.32,0,0,1-1.422-.164C9200.714-22224.1,9200.732-22224.029,9200.752-22223.959Z" transform="translate(-9186.242 22256.754)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#ffcfd1;}.b{opacity:0;}.b,.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18559 4825)"><rect class="b" width="42" height="42" transform="translate(-18554 -4704)"/><path class="c" d="M-9736.837-26950.139a1.008,1.008,0,0,1-.542-.889v-3.371h-.752a4.506,4.506,0,0,1-4.5-4.5v-2.629c-1.89-.08-3.366-2-3.366-4.367s1.477-4.287,3.366-4.369v-2.633a4.5,4.5,0,0,1,4.5-4.5h15.658v.129a3.676,3.676,0,0,0,.494,1.869h-16.152a2.5,2.5,0,0,0-2.5,2.5v14a2.5,2.5,0,0,0,2.5,2.5h1.741a1.006,1.006,0,0,1,1.009,1v2.432l4.544-3.244a.97.97,0,0,1,.576-.189h13.124a2.5,2.5,0,0,0,2.506-2.5v-9.441a3.524,3.524,0,0,0,1.118.189h.033a3.634,3.634,0,0,0,2.764-1.293,4.793,4.793,0,0,1,1.456,3.549,5.014,5.014,0,0,1-.982,3.041,3.23,3.23,0,0,1-2.391,1.334v2.621a4.507,4.507,0,0,1-4.5,4.5h-12.806l-5.858,4.184a1.021,1.021,0,0,1-.582.191A1.007,1.007,0,0,1-9736.837-26950.139Zm1.334-10.389a1.876,1.876,0,0,1-1.876-1.877v-7.869a1.876,1.876,0,0,1,1.876-1.877h15.739a1.876,1.876,0,0,1,1.876,1.877v7.869a1.876,1.876,0,0,1-1.876,1.877Zm10.931-5.811a1.752,1.752,0,0,0,1.754,1.746,1.751,1.751,0,0,0,1.747-1.746,1.754,1.754,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9724.572-26966.338Zm-9.617,0a1.752,1.752,0,0,0,1.748,1.746,1.751,1.751,0,0,0,1.747-1.746,1.755,1.755,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9734.189-26966.338Zm20.1-5.277-.453-1.551a4.433,4.433,0,0,0-2.946-3.006l-1.537-.467a.649.649,0,0,1-.447-.611.524.524,0,0,1,.021-.148.616.616,0,0,1,.217-.346.624.624,0,0,1,.217-.115l.284-.088,1.232-.365a4.417,4.417,0,0,0,2.96-3.02l.46-1.551a.625.625,0,0,1,.42-.434v.006a.538.538,0,0,1,.183-.033.574.574,0,0,1,.292.08.581.581,0,0,1,.3.381l.46,1.557a4.422,4.422,0,0,0,2.96,3.014l1.171.346.346.107a.647.647,0,0,1,.454.609.641.641,0,0,1-.447.611l-1.537.467a4.434,4.434,0,0,0-2.946,3.006l-.453,1.551a.631.631,0,0,1-.6.461A.636.636,0,0,1-9714.089-26971.615Zm-4.571-7.34-.183-.623a2.7,2.7,0,0,0-1.829-1.83l-.623-.189a.29.29,0,0,1-.2-.277.284.284,0,0,1,.2-.277l.61-.184a2.7,2.7,0,0,0,1.842-1.842l.183-.615a.32.32,0,0,1,.2-.2.327.327,0,0,1,.224.027.275.275,0,0,1,.143.17l.183.615a2.713,2.713,0,0,0,1.842,1.842l.609.184a.289.289,0,0,1,.21.277.3.3,0,0,1-.21.277l-.257.076-.366.113a2.725,2.725,0,0,0-1.828,1.83l-.183.623a.293.293,0,0,1-.278.2A.3.3,0,0,1-9718.66-26978.955Z" transform="translate(-8805.37 22282.029)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="1080" viewBox="0 0 1920 1080"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 3840 2160"><image width="3840" height="2160" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 1.7 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="582" height="667" viewBox="0 0 582 667"><image width="582" height="667" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 664 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" width="1" height="1" patternTransform="matrix(-1, 0, 0, 1, 278, 0)" viewBox="0 0 139 765"><image preserveAspectRatio="xMidYMid slice" width="139" height="765" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 51 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 278 1530"><image width="278" height="1530" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 51 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="273" height="323" viewBox="0 0 273 323"><image width="273" height="323" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 193 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="727" height="727" viewBox="0 0 727 727"><defs><style>.a{fill:url(#a);}.b{fill:url(#d);}.c,.d,.f{fill:none;}.c{stroke:rgba(32,194,255,0);stroke-width:8px;}.d{stroke:rgba(255,173,32,0.15);stroke-width:5px;stroke-dasharray:7 5;}.e{stroke:none;}.g{filter:url(#e);}.h{filter:url(#b);}</style><linearGradient id="a" x1="0.761" y1="0.205" x2="0.284" y2="0.581" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#ffd2ab"/><stop offset="1" stop-color="#ff7855"/></linearGradient><filter id="b" x="88.068" y="60.324" width="217.004" height="181.59" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="c"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><linearGradient id="d" x1="0.237" y1="0.761" x2="0.718" y2="0.394" xlink:href="#a"/><filter id="e" x="424.041" y="484.359" width="215.309" height="181.689" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="f"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter></defs><g transform="translate(4 4)"><g transform="translate(-126.998 -127.002)"><g class="h" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="a" d="M18115.566-21172.494q4.919-8.443,10.389-16.543a294.531,294.531,0,0,1,35.713-43.289,294.545,294.545,0,0,1,43.293-35.717,292.5,292.5,0,0,1,49.682-26.969,290.614,290.614,0,0,1,31.271-11.162l1.656,5.506a288.092,288.092,0,0,0-166.973,131.084Z" transform="translate(-18005 21389)"/></g><g class="g" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="b" d="M18451.539-20750.967a288.209,288.209,0,0,0,165.279-131.172l5.029,2.92q-5.1,8.815-10.8,17.258a294.659,294.659,0,0,1-35.717,43.287,294.647,294.647,0,0,1-43.293,35.717,292.2,292.2,0,0,1-49.686,26.971,291.1,291.1,0,0,1-29.178,10.537Z" transform="translate(-18005 21389)"/></g><circle class="c" cx="359.5" cy="359.5" r="359.5" transform="translate(126.998 127.002)"/></g><g class="d" transform="translate(98 98)"><circle class="e" cx="261.5" cy="261.5" r="261.5"/><circle class="f" cx="261.5" cy="261.5" r="259"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="727" height="727" viewBox="0 0 727 727"><defs><style>.a{fill:url(#a);}.b{fill:url(#d);}.c,.d,.f{fill:none;}.c{stroke:rgba(32,194,255,0);stroke-width:8px;}.d{stroke:rgba(255,173,32,0.15);stroke-width:5px;stroke-dasharray:7 5;}.e{stroke:none;}.g{filter:url(#e);}.h{filter:url(#b);}</style><linearGradient id="a" x1="0.761" y1="0.205" x2="0.284" y2="0.581" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#ffd2ab"/><stop offset="1" stop-color="#ff7855"/></linearGradient><filter id="b" x="88.068" y="60.324" width="217.004" height="181.59" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="c"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><linearGradient id="d" x1="0.237" y1="0.761" x2="0.718" y2="0.394" xlink:href="#a"/><filter id="e" x="424.041" y="484.359" width="215.309" height="181.689" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="f"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter></defs><g transform="translate(4 4)"><g transform="translate(-126.998 -127.002)"><g class="h" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="a" d="M18115.566-21172.494q4.919-8.443,10.389-16.543a294.531,294.531,0,0,1,35.713-43.289,294.545,294.545,0,0,1,43.293-35.717,292.5,292.5,0,0,1,49.682-26.969,290.614,290.614,0,0,1,31.271-11.162l1.656,5.506a288.092,288.092,0,0,0-166.973,131.084Z" transform="translate(-18005 21389)"/></g><g class="g" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="b" d="M18451.539-20750.967a288.209,288.209,0,0,0,165.279-131.172l5.029,2.92q-5.1,8.815-10.8,17.258a294.659,294.659,0,0,1-35.717,43.287,294.647,294.647,0,0,1-43.293,35.717,292.2,292.2,0,0,1-49.686,26.971,291.1,291.1,0,0,1-29.178,10.537Z" transform="translate(-18005 21389)"/></g><circle class="c" cx="359.5" cy="359.5" r="359.5" transform="translate(126.998 127.002)"/></g><g class="d" transform="translate(98 98)"><circle class="e" cx="261.5" cy="261.5" r="261.5"/><circle class="f" cx="261.5" cy="261.5" r="259"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="458" height="113.588" viewBox="0 0 458 113.588"><defs><style>.a{opacity:0.78;}.b{fill:url(#a);}.c{fill:#fff;}.d{filter:url(#d);}.e{filter:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff9c1"/></linearGradient><filter id="b" x="104.221" y="19.443" width="226.559" height="61.289" filterUnits="userSpaceOnUse"><feOffset dy="1" input="SourceAlpha"/><feGaussianBlur stdDeviation="5.5" result="c"/><feFlood flood-color="#fe0" flood-opacity="0.71"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><filter id="d" x="104.221" y="19.443" width="226.559" height="61.289" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="2" result="e"/><feFlood flood-color="#fff" result="f"/><feComposite operator="out" in="SourceGraphic" in2="e"/><feComposite operator="in" in="f"/><feComposite operator="in" in2="SourceGraphic"/></filter></defs><g transform="translate(-731 -564.412)"><image class="a" width="458" height="113.588" transform="translate(731 564.412)" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 625 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{opacity:0;fill:url(#a);}.b{fill:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient><linearGradient id="b" x1="0.405" x2="1" xlink:href="#a"/></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M110.023,105.37H98.2a1.721,1.721,0,0,1-1.716-1.716v-1.918h10.189a1.721,1.721,0,0,0,1.716-1.716V72.8a1.721,1.721,0,0,0-1.716-1.716H98.2V67.437A3.444,3.444,0,0,0,94.76,64H87.83a3.444,3.444,0,0,0-3.437,3.437v3.652H75.625A1.721,1.721,0,0,0,73.91,72.8v27.21a1.721,1.721,0,0,0,1.716,1.716h10.49v1.918a1.721,1.721,0,0,1-1.716,1.716H72.3a1.721,1.721,0,0,0-1.716,1.716v10.1A1.721,1.721,0,0,0,72.3,118.9h37.724a1.721,1.721,0,0,0,1.716-1.716v-10.1A1.726,1.726,0,0,0,110.023,105.37Zm-8.406-19.1a3.437,3.437,0,1,1-3.437-3.437A3.436,3.436,0,0,1,101.616,86.266ZM87.83,67.437h6.924v3.646H87.83ZM81.121,86.266A3.437,3.437,0,1,1,84.558,89.7,3.436,3.436,0,0,1,81.121,86.266Zm32.48-7.089V93.355a1.716,1.716,0,0,1-3.431,0V79.177a1.716,1.716,0,0,1,3.431,0Zm5.122,3.548v6.881a1.716,1.716,0,0,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0ZM70.644,95.07a1.717,1.717,0,0,1-1.716-1.716V79.177a1.716,1.716,0,0,1,3.431,0V93.355A1.713,1.713,0,0,1,70.644,95.07ZM67.231,82.724v6.881a1.716,1.716,0,1,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0Zm0,0" transform="translate(-14540.154 22987.455)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="188" height="241" viewBox="0 0 188 241"><defs><style>.a{fill:url(#a);}.b{fill:#fff;opacity:0.47;}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 376 482"><image width="376" height="482" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 68 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.431" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(-71.077 -67.746)"><g class="a" transform="translate(71.077 67.746)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M114.406,106.791a7.707,7.707,0,0,0-4.354,1.353L98.7,99.937a13.3,13.3,0,0,0,1.742-6.583c0-.421-.03-.842-.06-1.263L112,85.207a4.687,4.687,0,1,0-1.952-2.345L99.691,88.995a13.678,13.678,0,0,0-6.1-7.365l2.072-10.341c.15,0,.3.03.451.03a4.66,4.66,0,1,0-4.655-4.659,4.727,4.727,0,0,0,1.412,3.367l-2.1,10.462A13.479,13.479,0,0,0,80.05,81.87l-6.4-5.712A6.129,6.129,0,1,0,71.7,78.443L77.677,83.7a13.456,13.456,0,0,0,.691,19.991l-5.316,5.622a5.948,5.948,0,0,0-3.394-1.022,6.163,6.163,0,1,0,6.156,6.162,6.343,6.343,0,0,0-.721-2.916l5.826-6.193a13.464,13.464,0,0,0,16.1-2.946l11.022,7.966a7.77,7.77,0,0,0-1.2,4.118,7.658,7.658,0,1,0,15.316,0A7.817,7.817,0,0,0,114.406,106.791Zm0,0" transform="translate(13 9.671)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,13 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68">
<defs>
<linearGradient id="ap-idea" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f3212c"/>
<stop offset="1" stop-color="#aa071a"/>
</linearGradient>
</defs>
<g fill="url(#ap-idea)" transform="translate(12 10)">
<path d="M22 2.2A12.8 12.8 0 0 0 9.2 15c0 5.1 2.9 9.5 7.1 11.6v3.8a2.4 2.4 0 0 0 2.4 2.4h6.6a2.4 2.4 0 0 0 2.4-2.4v-3.8A12.8 12.8 0 0 0 34.8 15 12.8 12.8 0 0 0 22 2.2Zm3.3 26.8h-6.6v-2.1h6.6Zm-3.3-26.8A10.4 10.4 0 0 1 32.4 15a10.4 10.4 0 0 1-6.3 9.5 2.4 2.4 0 0 0-1.3 2.1v.3h-5.6v-.3a2.4 2.4 0 0 0-1.3-2.1A10.4 10.4 0 0 1 11.6 15 10.4 10.4 0 0 1 22 2.2Z"/>
<path d="M17.6 39.2a2 2 0 0 0 2 2h4.8a2 2 0 0 0 2-2v-1.4h-8.8Zm-1.8-3.8h12.4a1.6 1.6 0 1 0 0-3.2H15.8a1.6 1.6 0 1 0 0 3.2Z"/>
<path d="M8.4 22.6a1.6 1.6 0 0 0 0-3.2H3.8a1.6 1.6 0 1 0 0 3.2Zm31.8 0a1.6 1.6 0 0 0 0-3.2h-4.6a1.6 1.6 0 1 0 0 3.2ZM7.2 10.8a1.6 1.6 0 0 0 2.3-2.3L6.2 5.3A1.6 1.6 0 0 0 4 7.6Zm29.3-2.3a1.6 1.6 0 0 0 2.3 2.3l3.2-3.2A1.6 1.6 0 1 0 39.7 5.3Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M43.013,57.336h-.255l-.074,0a14.064,14.064,0,0,1-8.911-3.467,6.216,6.216,0,0,1,6.1-5.029h6.278a6.218,6.218,0,0,1,6.1,5.03A14.073,14.073,0,0,1,43.6,57.324h-.009l-.067,0H43.5l-.063,0h-.424ZM30.159,54.9H8.5a1.717,1.717,0,0,1-1.715-1.716v-10.1A1.717,1.717,0,0,1,8.5,41.363H20.6a1.717,1.717,0,0,0,1.716-1.715V37.73H11.824a1.717,1.717,0,0,1-1.716-1.715V8.8a1.718,1.718,0,0,1,1.716-1.716h8.768V3.437A3.44,3.44,0,0,1,24.029,0h6.93A3.441,3.441,0,0,1,34.4,3.437V7.089H42.87A1.718,1.718,0,0,1,44.586,8.8V26.022c-.515-.046-1.044-.07-1.574-.07A17.327,17.327,0,0,0,30.157,54.9Zm4.219-36.07a3.437,3.437,0,1,0,3.438,3.437A3.441,3.441,0,0,0,34.378,18.828Zm-13.619,0A3.437,3.437,0,1,0,24.2,22.265,3.441,3.441,0,0,0,20.758,18.828ZM24.029,3.437V7.083h6.924V3.437Zm7.256,47.59v0a14.059,14.059,0,1,1,23.456,0,9.508,9.508,0,0,0-8.589-5.455H44.686a7.193,7.193,0,1,0-3.347,0H39.873a9.5,9.5,0,0,0-8.587,5.457ZM43.013,42.5a3.923,3.923,0,1,1,3.923-3.924A3.928,3.928,0,0,1,43.013,42.5ZM6.844,31.07a1.717,1.717,0,0,1-1.716-1.715V15.176a1.715,1.715,0,1,1,3.431,0V29.355A1.717,1.717,0,0,1,6.844,31.07ZM49.8,27.327h0a17.187,17.187,0,0,0-3.429-1.051v-11.1a1.715,1.715,0,1,1,3.431,0v12.15Zm3.406-.007a1.717,1.717,0,0,1-1.715-1.715V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,53.206,27.32Zm-51.491,0A1.717,1.717,0,0,1,0,25.605V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,1.715,27.32Z" transform="translate(-14477.664 23050.15)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1,14 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68">
<defs>
<linearGradient id="ap-task" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f3212c"/>
<stop offset="1" stop-color="#aa071a"/>
</linearGradient>
</defs>
<g fill="url(#ap-task)" transform="translate(14 12)">
<path d="M28.4 2.2H15.6A3.4 3.4 0 0 0 12.2 5.6v2.8H8.6A3.4 3.4 0 0 0 5.2 11.8v28.8A3.4 3.4 0 0 0 8.6 44h22.8a3.4 3.4 0 0 0 3.4-3.4V11.8a3.4 3.4 0 0 0-3.4-3.4h-3.6V5.6A3.4 3.4 0 0 0 28.4 2.2Zm-12.8 3.4h12.8v2.8H15.6Zm19.2 35.8H8.6V11.8h3.6v2.2a1.6 1.6 0 0 0 1.6 1.6h12.8a1.6 1.6 0 0 0 1.6-1.6v-2.2h3.6Z"/>
<rect x="11.4" y="24.2" width="3.6" height="11.6" rx="1.2"/>
<rect x="18.2" y="20.4" width="3.6" height="15.4" rx="1.2"/>
<rect x="25" y="27.2" width="3.6" height="8.6" rx="1.2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 924 B

+3 -13
View File
@@ -40,7 +40,7 @@ window.__CM_RUNTIME_CONFIG__ = {
// Canvas/AI 写作独立 LangGraph 地址:为空时前端会回退使用 VITE_LANGGRAPH_BASE_URL。
VITE_CANVAS_LANGGRAPH_BASE_URL: "",
// 地图瓦片地址模板:仅供普通问答消息列表中的交互地图使用。
// 地图瓦片地址模板:普通问答地图和生成的 HTML 网页地图共同使用。
// 后续接入内网瓦片服务时,只需替换此项并保留 {z}/{x}/{y} 占位符。
VITE_MAP_TILE_URL: "http://119.254.86.251:8023/tiles/{z}/{x}/{y}.png?v=zh-z14-13",
@@ -98,10 +98,10 @@ window.__CM_RUNTIME_CONFIG__ = {
VITE_AIPI_MOPECHAT_URL: "https://ch1.b.uat.4.cn/likun_b1_mope",
// 工作室/空间后端接口:空间列表、空间详情、素材上传等使用。
VITE_AIPI_BACKENP_URL: "https://knowledgetoolserver.b.uat.4.cn",
VITE_AIPI_BACKENP_URL: "http://47.88.25.99:8000",
// 工作室/空间后端别名:兼容旧配置命名,通常与 VITE_AIPI_BACKENP_URL 保持一致。
VITE_NOTEBOOK_API_BASE_URL: "https://knowledgetoolserver.b.uat.4.cn",
VITE_NOTEBOOK_API_BASE_URL: "http://47.88.25.99:8000",
// 工作室/空间前端地址:用于 auth/callback、新建对话等跳转。
VITE_AIPI_FRONTEND_URL: "http://47.88.25.99:3000",
@@ -155,16 +155,6 @@ window.__CM_RUNTIME_CONFIG__ = {
// GitHub OAuth Token;不使用 GitHub 相关能力时留空。
VITE_GITHUB_OAUTH_TOKEN: "",
// 对话历史页「收藏」右侧的「清空」按钮。
// "false" 隐藏;不填、删掉这一项,或填其它值,都显示。
// 确认后会删除当前账号的全部对话,以及该账号下所有智能体的聊天记录。
VITE_CHAT_HISTORY_CLEAR_VISIBLE: "true",
// 是否在问答输入框「模式」菜单显示「极速」:"true" 显示,"false" 隐藏。
// 默认关闭。开启后可直连大模型流式问答,不走智能体工具与技能。
// 部署后改 dist/runtime-config.js 再刷新页面即可,无需重新打包。
VITE_TURBO_MODE_VISIBLE: "true",
// 是否在智能体管理页显示「舆情分析」类型:"true" 显示,"false" 隐藏。
// 关闭后,该智能体的专用对话地址也会自动跳回智能体管理页。
VITE_SENTIMENT_AGENT_VISIBLE: "true",
+2 -64
View File
@@ -28,8 +28,8 @@ const requiredLegacyFallbacks = [
},
{
file: "src/components/ai-elements/prompt-input.tsx",
pattern: /<InputGroup className="h-auto min-h-16 flex-col items-stretch">/,
description: "Prompt textarea must not rely on :has() for its layout",
pattern: /<InputGroup className="h-auto min-h-16">/,
description: "Prompt textarea must not rely on :has() for its parent height",
},
{
file: "src/core/utils/mermaid.ts",
@@ -41,68 +41,6 @@ const requiredLegacyFallbacks = [
pattern: /export function downlevelModernColors[\s\S]*function injectLegacyChartShim/,
description: "Generated HTML charts must downlevel modern CSS colors for Chrome 109",
},
{
file: "src/pages/ChatPage.tsx",
pattern: /chat-landing-composer-offset[\s\S]*chat-landing-content-lift/,
description: "Chat landing layout must not rely on Tailwind's individual translate property",
},
{
file: "src/styles/globals.css",
pattern: /\.chat-landing-composer-offset\s*\{\s*position:\s*relative;\s*top:\s*calc\(96px\s*-\s*50vh\);\s*\}/,
description: "Chat landing composer must offset with top, not Tailwind translate",
},
{
file: "src/styles/globals.css",
pattern:
/\.legacy-dialog-viewport\s*\{[\s\S]*?display:\s*flex;[\s\S]*?align-items:\s*center;[\s\S]*?justify-content:\s*center;/,
description: "Dialog content must be flex-centered without Tailwind translate",
},
{
file: "src/components/ui/dialog.tsx",
pattern: /legacy-dialog-viewport[\s\S]*relative grid/,
description: "Dialog panel must not use fixed + translate centering",
},
{
file: "src/styles/globals.css",
pattern:
/\.legacy-dialog-viewport\s*>\s*\[data-slot="dialog-content"\]\s*\{[\s\S]*?min-height:\s*0;[\s\S]*?max-height:\s*100%;/,
description: "Flex-centered dialogs must keep min-height:0 so inner scroll works",
},
{
file: "src/styles/globals.css",
pattern: /\.legacy-floating-layer\s*\{\s*z-index:\s*300;/,
description: "Portaled select/dropdown layers must sit above dialog overlay z-index 200",
},
{
file: "src/components/workspace/skills/skill-file-preview-dialog.tsx",
pattern: /minHeight:[\s\S]*100vh[\s\S]*maxHeight:[\s\S]*100vh/,
description: "Skill file preview must size with vh, not dvh, for Chrome 102",
},
{
file: "src/core/compat/abort-signal.ts",
pattern: /export function installAbortSignalTimeout[\s\S]*AbortSignal/,
description: "LangGraph SDK timeoutMs needs AbortSignal.timeout for Chrome 102",
},
{
file: "src/core/api/api-client.ts",
pattern: /function installLegacyControlTimeout[\s\S]*AbortSignal\.timeout/,
description: "Chat send must skip AbortSignal.timeout when Chrome 102 lacks it",
},
{
file: "index.html",
pattern: /AbortSignal\.timeout = function/,
description: "Chrome 102 needs AbortSignal.timeout before any module loads",
},
{
file: "src/styles/globals.css",
pattern: /\.workspace-chat-bg,\s*\n\s*\.canvas-writing-bg\s*\{\s*background-color:\s*var\(--background\);/,
description: "Agent chat canvas needs an explicit token background for Chrome 102",
},
{
file: "src/styles/globals.css",
pattern: /@supports not \(translate: 0\)[\s\S]*\.dialog-content-center\s*\{\s*transform:\s*translate\(-50%,\s*-50%\);/,
description: "Dialog centering needs a transform fallback for Chrome 102",
},
];
for (const file of cssFiles) {
@@ -1,39 +0,0 @@
import { spawnSync } from "node:child_process";
import { mkdirSync, mkdtempSync } from "node:fs";
import { createRequire } from "node:module";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
const require = createRequire(import.meta.url);
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const { build } = await import(pathToFileURL(require.resolve("esbuild", {
paths: [dirname(require.resolve("vite"))],
})).href);
const output = join(root, ".runtime", "ui-boundary-check");
mkdirSync(output, { recursive: true });
await build({
absWorkingDir: root,
entryPoints: ["src/components/react-ui-error-boundary.browser-check.tsx"],
bundle: true,
platform: "browser",
format: "iife",
define: { "process.env.NODE_ENV": JSON.stringify("production") },
outfile: join(output, "check.js"),
});
const browser = process.env.CHROME_PATH || (process.platform === "win32"
? "C:/Program Files/Google/Chrome/Application/chrome.exe"
: "/usr/bin/chromium");
const response = spawnSync(browser, [
"--headless=new", "--disable-gpu", "--disable-background-networking", "--no-first-run",
`--user-data-dir=${mkdtempSync(join(output, "browser-profile-"))}`,
"--virtual-time-budget=3000", "--dump-dom",
pathToFileURL(join(root, "scripts", "react-ui-error-boundary-check.html")).href,
], { encoding: "utf8", windowsHide: true, timeout: 30_000 });
if (response.error) throw response.error;
const payload = response.stdout?.match(/<pre id="boundary-check-result">([^<]+)<\/pre>/)?.[1];
if (!payload || response.status !== 0) {
throw new Error(`Browser check did not finish: exit=${response.status}; ${response.stderr?.slice(-500)}`);
}
const result = JSON.parse(payload);
if (result.passed !== true) throw new Error(`Browser check failed: ${payload}`);
console.log("React production boundary browser check:", result);
@@ -1,8 +0,0 @@
<!doctype html>
<html lang="zh-CN">
<head><meta charset="utf-8"><title>Offline React UI boundary check</title></head>
<body>
<div id="root"></div>
<script src="../.runtime/ui-boundary-check/check.js"></script>
</body>
</html>
-34
View File
@@ -1,34 +0,0 @@
import { spawnSync } from "node:child_process";
import { createRequire } from "node:module";
import path from "node:path";
import { fileURLToPath } from "node:url";
const root = fileURLToPath(new URL("../", import.meta.url));
const require = createRequire(import.meta.url);
// Resolve Vite's installed dependency directly: pnpm does not expose a
// transitive esbuild binary in node_modules/.bin, and tests must run offline.
const viteRequire = createRequire(require.resolve("vite/package.json"));
const { build, stop } = viteRequire("esbuild");
const testNames = ["login-entry", "session-validation"];
const outputDirectory = path.join(root, ".runtime/unit-tests");
try {
await build({
absWorkingDir: root,
entryPoints: testNames.map((name) => `src/core/auth/${name}.test.ts`),
outdir: outputDirectory,
outExtension: { ".js": ".mjs" },
bundle: true,
platform: "node",
format: "esm",
});
} finally {
stop();
}
const result = spawnSync(process.execPath, ["--test", ...testNames.map((name) => path.join(outputDirectory, `${name}.test.mjs`))], {
cwd: root,
stdio: "inherit",
});
if (result.error) throw result.error;
process.exitCode = result.status ?? 1;
+79 -114
View File
@@ -1,13 +1,11 @@
import { lazy, Suspense, useEffect, useMemo } from "react";
import { useEffect, useMemo } from "react";
import { Navigate, Route, Routes } from "react-router-dom";
import { ThemeProvider as NextThemesProvider } from "next-themes";
import { DesensitizeWordsLoader } from "@/components/desensitize-words-loader";
import { FontScaleApplier } from "@/components/font-scale";
import { QueryClientProvider } from "@/components/query-client-provider";
import { RouteLoadingFallback } from "@/components/route-loading";
import { AuthSyncWatcher } from "@/core/auth/sync";
import { RequireAccount } from "@/core/auth/require-account";
import { I18nProvider } from "@/core/i18n/context";
import { fetchYLogConfig } from "@/core/log/y-log-config";
import { detectLocale } from "@/core/i18n/locale";
@@ -27,47 +25,28 @@ import {
import { HashRouter, useLocation } from "react-router-dom";
import LandingPage from "./pages/LandingPage";
import LoginPage from "./pages/LoginPage";
import PageRoutes from "./pages/PageRoutes";
import PublicScheduledTaskPage, {
PublicScheduledTaskFullscreenPage,
} from "./pages/PublicScheduledTaskPage";
import PublicSharePage from "./pages/PublicSharePage";
import PublicLeaderboardPage from "./pages/PublicLeaderboardPage";
import PublicRoundtableSharePage from "./pages/PublicRoundtableSharePage";
import EmbedChatPage from "./pages/EmbedChatPage";
import EmbedRoundtablePage from "./pages/EmbedRoundtablePage";
import SiteStudioPage from "./pages/site-studio/SiteStudioPage";
import DashboardStandalonePage from "@/roundtable-planning/pages/DashboardStandalonePage";
import PositionRoundtablePage from "@/position-roundtable/pages/PositionRoundtablePage";
import WeKnoraWikiPageView from "@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiPageView";
import {
isPositionRoundtableStandaloneMode,
POSITION_ROUNDTABLE_ROUTE,
} from "@/position-roundtable/demo/position-roundtable-demo-config";
const LandingPage = lazy(() => import("./pages/LandingPage"));
const LoginPage = lazy(() => import("./pages/LoginPage"));
const RegisterPage = lazy(() => import("./pages/RegisterPage"));
const PageRoutes = lazy(() => import("./pages/PageRoutes"));
const PublicScheduledTaskPage = lazy(() => import("./pages/PublicScheduledTaskPage"));
const PublicScheduledTaskFullscreenPage = lazy(() =>
import("./pages/PublicScheduledTaskPage").then((module) => ({
default: module.PublicScheduledTaskFullscreenPage,
})),
);
const PublicSharePage = lazy(() => import("./pages/PublicSharePage"));
const PublicLeaderboardPage = lazy(() => import("./pages/PublicLeaderboardPage"));
const PublicRoundtableSharePage = lazy(() => import("./pages/PublicRoundtableSharePage"));
const EmbedChatPage = lazy(() => import("./pages/EmbedChatPage"));
const EmbedRoundtablePage = lazy(() => import("./pages/EmbedRoundtablePage"));
const SiteStudioPage = lazy(() => import("./pages/site-studio/SiteStudioPage"));
const DashboardStandalonePage = lazy(
() => import("@/roundtable-planning/pages/DashboardStandalonePage"),
);
const PositionRoundtablePage = lazy(
() => import("@/position-roundtable/pages/PositionRoundtablePage"),
);
const WeKnoraWikiPageView = lazy(
() => import("@/strategy-components/components/resource-management/llmwiki/WeKnoraWikiPageView"),
);
const ChatRuntime = lazy(() =>
import("@/components/workspace/chat-runtime").then((module) => ({
default: module.ChatRuntime,
})),
);
const NotFoundPage = lazy(() =>
import("./pages/NotFoundPage").then((module) => ({
default: module.NotFoundPage,
})),
);
const OfficialDeerFlowEntry = lazy(() => import("./pages/OfficialDeerFlowEntry"));
import { ChatRuntime } from "./pages/WorkspaceRoutes";
import { NotFoundPage } from "./pages/NotFoundPage";
import OfficialDeerFlowEntry from "./pages/OfficialDeerFlowEntry";
const PUBLIC_EMBED_PREFIXES = [
"/share/",
@@ -166,86 +145,72 @@ export function App() {
<Navigate to={POSITION_ROUNDTABLE_ROUTE} replace />
);
const pageElement = positionStandaloneMode ? (
<RequireAccount allowLegacyAnonymous>
<ChatRuntime>
<PositionRoundtablePage compactChrome />
</ChatRuntime>
</RequireAccount>
<ChatRuntime>
<PositionRoundtablePage compactChrome />
</ChatRuntime>
) : (
<RequireAccount><PageRoutes /></RequireAccount>
<PageRoutes />
);
return (
<HashRouter>
<AppProviders>
<Suspense fallback={<RouteLoadingFallback />}>
<Routes>
<Route path="/" element={<RootRedirect />} />
<Route
path="/login"
element={
positionStandaloneMode ? standaloneLoginRedirect : <LoginPage />
}
/>
<Route
path="/login/:username"
element={
positionStandaloneMode ? standaloneLoginRedirect : <LoginPage />
}
/>
<Route
path="/register"
element={
positionStandaloneMode ? standaloneLoginRedirect : <RegisterPage />
}
/>
<Route path="/landing" element={<LandingPage />} />
<Route path="/share/:shareCode" element={<PublicSharePage />} />
<Route path="/public/leaderboard" element={<PublicLeaderboardPage />} />
<Route
path="/roundtable-share/:shareCode"
element={<PublicRoundtableSharePage view="landing" />}
/>
<Route
path="/roundtable-share/:shareCode/report"
element={<PublicRoundtableSharePage view="report" />}
/>
<Route
path="/roundtable-share/:shareCode/dashboard"
element={<PublicRoundtableSharePage view="dashboard" />}
/>
<Route
path="/public/scheduled-tasks/:taskId"
element={<PublicScheduledTaskPage />}
/>
<Route
path="/public/scheduled-tasks/:taskId/runs/:runId/fullscreen"
element={<PublicScheduledTaskFullscreenPage />}
/>
<Route
path="/embed/chats/:thread_id"
element={
<ChatRuntime>
<EmbedChatPage />
</ChatRuntime>
}
/>
<Route path="/embed/roundtable" element={<EmbedRoundtablePage />} />
<Route
path="/embed/knowledge/:noteId"
element={<WeKnoraWikiPageView publicEmbed />}
/>
<Route
path="/roundtable-dashboard"
element={<RequireAccount><DashboardStandalonePage /></RequireAccount>}
/>
<Route path="/official/*" element={<RequireAccount><OfficialDeerFlowEntry /></RequireAccount>} />
{/* Web App 站点预览工作室:独立路由 + 独立视觉风格(无主应用 chrome) */}
<Route path="/sites/:threadId/:siteName" element={<RequireAccount><SiteStudioPage /></RequireAccount>} />
<Route path="/page/*" element={pageElement} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</Suspense>
<Routes>
<Route path="/" element={<RootRedirect />} />
<Route
path="/login"
element={positionStandaloneMode ? standaloneLoginRedirect : <LoginPage />}
/>
<Route
path="/login/:username"
element={positionStandaloneMode ? standaloneLoginRedirect : <LoginPage />}
/>
<Route path="/landing" element={<LandingPage />} />
<Route path="/share/:shareCode" element={<PublicSharePage />} />
<Route path="/public/leaderboard" element={<PublicLeaderboardPage />} />
<Route
path="/roundtable-share/:shareCode"
element={<PublicRoundtableSharePage view="landing" />}
/>
<Route
path="/roundtable-share/:shareCode/report"
element={<PublicRoundtableSharePage view="report" />}
/>
<Route
path="/roundtable-share/:shareCode/dashboard"
element={<PublicRoundtableSharePage view="dashboard" />}
/>
<Route
path="/public/scheduled-tasks/:taskId"
element={<PublicScheduledTaskPage />}
/>
<Route
path="/public/scheduled-tasks/:taskId/runs/:runId/fullscreen"
element={<PublicScheduledTaskFullscreenPage />}
/>
<Route
path="/embed/chats/:thread_id"
element={
<ChatRuntime>
<EmbedChatPage />
</ChatRuntime>
}
/>
<Route path="/embed/roundtable" element={<EmbedRoundtablePage />} />
<Route
path="/embed/knowledge/:noteId"
element={<WeKnoraWikiPageView publicEmbed />}
/>
<Route
path="/roundtable-dashboard"
element={<DashboardStandalonePage />}
/>
<Route path="/official/*" element={<OfficialDeerFlowEntry />} />
{/* Web App 站点预览工作室:独立路由 + 独立视觉风格(无主应用 chrome) */}
<Route path="/sites/:threadId/:siteName" element={<SiteStudioPage />} />
<Route path="/page/*" element={pageElement} />
<Route path="*" element={<NotFoundPage />} />
</Routes>
</AppProviders>
</HashRouter>
);
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="53" height="53" viewBox="0 0 53 53"><defs><style>.a{fill:#fddadc;stroke:#f86c73;stroke-dasharray:4;}.b{fill:#fff;opacity:0;}.c{fill:url(#a);}</style><linearGradient id="a" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0.5 -109.5)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 110)"/><g transform="translate(6.5 116.5)"><rect class="b" width="39" height="39"/><path class="c" d="M20.72,28.846a8.938,8.938,0,0,1-7.044-14.437c.01-.014.02-.025.029-.037s.026-.035.04-.051l.02-.025.017-.02.012-.014c.01-.012.021-.023.03-.037l.015-.018a.179.179,0,0,0,.021-.025l.011-.012a.139.139,0,0,1,.011-.012l.064-.078.026-.031A.221.221,0,0,0,14,14.021a8.936,8.936,0,0,1,12.315-1.082c.093.072.181.146.279.234,0,0,0,0,.008.006.023.021.048.041.07.063a.393.393,0,0,1,.037.033c.015.012.028.025.041.037l.016.016a.055.055,0,0,1,.013.01l.014.012.014.012a.043.043,0,0,0,.008.01l0,0a8.964,8.964,0,0,1,2.719,5.055l0,.014c0,.031.01.061.015.09l0,.016,0,.016c0,.021.007.045.011.066l0,.018v0a.04.04,0,0,1,0,.01l0,.016,0,.018,0,.016c0,.018,0,.035.006.053a.171.171,0,0,1,0,.031c.011.078.02.158.026.238l.008.07v.018c0,.016,0,.029,0,.045a.106.106,0,0,0,0,.018.108.108,0,0,1,0,.018.28.28,0,0,0,0,.035l0,.051v.006c0,.021,0,.045,0,.064s0,.02,0,.029a.064.064,0,0,1,0,.014v.014c0,.021,0,.041,0,.063v.014c0,.01,0,.02,0,.029v.018c0,.025,0,.049,0,.074s0,.033,0,.049a.131.131,0,0,0,0,.02V19.7c0,.016,0,.027,0,.043v.041c0,.041,0,.082,0,.123A8.947,8.947,0,0,1,20.72,28.846Zm-3.574-9.953a1.016,1.016,0,0,0,0,2.031H19.7v2.563a1.016,1.016,0,0,0,2.031,0V20.924h2.563a1.016,1.016,0,0,0,0-2.031H21.73V16.334a1.016,1.016,0,0,0-2.031,0v2.559Zm-6.872,9.547H2.726A2.731,2.731,0,0,1,0,25.709V18.166a2.728,2.728,0,0,1,2.726-2.725h7.548a2.736,2.736,0,0,1,1.336.35A10.015,10.015,0,0,0,12.954,26.2,2.727,2.727,0,0,1,10.273,28.439ZM2.726,17.877a.292.292,0,0,0-.289.289v7.543A.293.293,0,0,0,2.726,26h7.548a.292.292,0,0,0,.289-.295V18.166a.292.292,0,0,0-.289-.289ZM10.273,13H2.726A2.731,2.731,0,0,1,0,10.273V2.73A2.731,2.731,0,0,1,2.726,0h7.548A2.731,2.731,0,0,1,13,2.73v7.543A2.731,2.731,0,0,1,10.273,13Zm17.09-.559v0a9.929,9.929,0,0,0-3.091-1.881H25.71A.288.288,0,0,0,26,10.273V2.73a.288.288,0,0,0-.288-.289H18.166a.286.286,0,0,0-.289.289v7.543c0,.014,0,.027,0,.049a9.841,9.841,0,0,0-2.246.979,2.737,2.737,0,0,1-.2-1.027V2.73A2.734,2.734,0,0,1,18.166,0H25.71a2.733,2.733,0,0,1,2.729,2.73v7.543a2.709,2.709,0,0,1-1.075,2.17Z" transform="translate(5.281 5.278)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1,10 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="52" height="52" viewBox="0 0 52 52">
<defs>
<linearGradient id="ap-add" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f5222d"/>
<stop offset="1" stop-color="#a8071a"/>
</linearGradient>
</defs>
<rect width="52" height="52" rx="8" fill="#ffcfd1"/>
<path fill="url(#ap-add)" d="M26 14a2 2 0 0 1 2 2v8h8a2 2 0 1 1 0 4h-8v8a2 2 0 1 1-4 0v-8h-8a2 2 0 1 1 0-4h8v-8a2 2 0 0 1 2-2z"/>
</svg>

Before

Width:  |  Height:  |  Size: 503 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#ffcfd1;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(2.236 118.236)"><path class="b" d="M9204.336-22218.762a6.4,6.4,0,0,1-2.489-.691,6.242,6.242,0,0,1-2-1.615,6.363,6.363,0,0,1-1.206-2.283,6.357,6.357,0,0,1-.246-1.863c-.047-.033-.094-.066-.139-.1a6.4,6.4,0,0,1-2.272-3.4,6.418,6.418,0,0,1,.268-4.076,6.336,6.336,0,0,1,1.233-1.912,6.383,6.383,0,0,1-.4-1.973,6.41,6.41,0,0,1,.53-2.809,6.441,6.441,0,0,1,1.7-2.289,6.424,6.424,0,0,1,1.751-1.057,4.969,4.969,0,0,1,.343-1.289,4.965,4.965,0,0,1,1.334-1.859,5.038,5.038,0,0,1,2.016-1.082,5.037,5.037,0,0,1,2.289-.074,5.024,5.024,0,0,1,2.089.943,4.947,4.947,0,0,1,.871.861,5.147,5.147,0,0,1,.876-.861,5,5,0,0,1,2.083-.943,5.035,5.035,0,0,1,2.289.074,5.06,5.06,0,0,1,2.021,1.082,5.031,5.031,0,0,1,1.334,1.859,5.008,5.008,0,0,1,.343,1.289,6.424,6.424,0,0,1,1.751,1.057,6.441,6.441,0,0,1,1.7,2.289,6.405,6.405,0,0,1,.524,2.809,6.434,6.434,0,0,1-.4,1.973,6.315,6.315,0,0,1,1.234,1.912,6.418,6.418,0,0,1,.268,4.076,6.4,6.4,0,0,1-2.272,3.4l-.143.105a6.214,6.214,0,0,1-.248,1.859,6.26,6.26,0,0,1-1.2,2.283,6.271,6.271,0,0,1-2.01,1.615,6.354,6.354,0,0,1-2.485.691c-.14.006-.278.012-.418.012a6.213,6.213,0,0,1-2.139-.375,6.394,6.394,0,0,1-2.2-1.34,6.4,6.4,0,0,1-.915-1.066,6.415,6.415,0,0,1-.91,1.066,6.427,6.427,0,0,1-2.206,1.34,6.283,6.283,0,0,1-2.143.377C9204.609-22218.748,9204.473-22218.752,9204.336-22218.762Zm6.768-6.342a4.232,4.232,0,0,0,.346,1.652,4.123,4.123,0,0,0,.972,1.379,4.116,4.116,0,0,0,1.44.877,4.062,4.062,0,0,0,1.67.234,4.159,4.159,0,0,0,1.63-.447,4.159,4.159,0,0,0,1.313-1.061,4.227,4.227,0,0,0,.787-1.49c.02-.07.037-.139.054-.209a6.32,6.32,0,0,1-1.422.164,1.1,1.1,0,0,1-1.1-1.1,1.1,1.1,0,0,1,1.1-1.1,4.178,4.178,0,0,0,2.529-.859,4.138,4.138,0,0,0,1.485-2.221,4.216,4.216,0,0,0-.173-2.67,4.2,4.2,0,0,0-1.765-2.01,1.1,1.1,0,0,1-.4-1.5,1.1,1.1,0,0,1,1.063-.543,4.16,4.16,0,0,0,.1-.758,4.249,4.249,0,0,0-.346-1.838,4.156,4.156,0,0,0-1.117-1.5,4.078,4.078,0,0,0-.569-.408,4.928,4.928,0,0,1-.385.838,1.1,1.1,0,0,1-.955.553,1.08,1.08,0,0,1-.547-.15,1.093,1.093,0,0,1-.4-1.5,2.906,2.906,0,0,0,.374-1.229,1.022,1.022,0,0,1,.006-.145,2.841,2.841,0,0,0-.218-1.133,2.836,2.836,0,0,0-.754-1.051,2.794,2.794,0,0,0-1.139-.607,2.8,2.8,0,0,0-1.29-.045,2.782,2.782,0,0,0-1.173.535,2.84,2.84,0,0,0-.82.994,2.912,2.912,0,0,0-.3,1.262v5.254a4.426,4.426,0,0,0,.877,2.625,4.4,4.4,0,0,0,2.277,1.58,1.1,1.1,0,0,1,.748,1.361,1.1,1.1,0,0,1-1.367.748,6.6,6.6,0,0,1-2.535-1.41v6.928Zm-10.352,1.145a4.119,4.119,0,0,0,.787,1.49,4.148,4.148,0,0,0,1.313,1.061,4.105,4.105,0,0,0,1.624.447,4.076,4.076,0,0,0,1.676-.234,4.125,4.125,0,0,0,1.44-.877,4.208,4.208,0,0,0,.972-1.379,4.226,4.226,0,0,0,.34-1.652v-6.924a6.628,6.628,0,0,1-2.534,1.406,1.117,1.117,0,0,1-.308.045,1.1,1.1,0,0,1-1.055-.793,1.093,1.093,0,0,1,.748-1.361,4.393,4.393,0,0,0,2.272-1.58,4.354,4.354,0,0,0,.876-2.625v-5.254a2.906,2.906,0,0,0-.29-1.262,2.84,2.84,0,0,0-.82-.994,2.778,2.778,0,0,0-1.179-.535,2.8,2.8,0,0,0-1.29.045,2.832,2.832,0,0,0-1.139.607,2.821,2.821,0,0,0-.748,1.051,2.819,2.819,0,0,0-.212,1.271,2.821,2.821,0,0,0,.374,1.234,1.1,1.1,0,0,1-.4,1.5,1.1,1.1,0,0,1-1.5-.4,5.009,5.009,0,0,1-.386-.838,4.127,4.127,0,0,0-.568.408,4.156,4.156,0,0,0-1.117,1.5,4.249,4.249,0,0,0-.346,1.838,4.246,4.246,0,0,0,.1.758,1.106,1.106,0,0,1,1.064.543,1.1,1.1,0,0,1-.4,1.5,4.2,4.2,0,0,0-1.765,2.01,4.216,4.216,0,0,0-.173,2.67,4.138,4.138,0,0,0,1.485,2.221,4.178,4.178,0,0,0,2.529.859,1.1,1.1,0,0,1,1.1,1.1,1.1,1.1,0,0,1-1.1,1.1,6.32,6.32,0,0,1-1.422-.164C9200.714-22224.1,9200.732-22224.029,9200.752-22223.959Z" transform="translate(-9186.242 22256.754)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#ffcfd1;}.b{opacity:0;}.b,.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18559 4825)"><rect class="b" width="42" height="42" transform="translate(-18554 -4704)"/><path class="c" d="M-9736.837-26950.139a1.008,1.008,0,0,1-.542-.889v-3.371h-.752a4.506,4.506,0,0,1-4.5-4.5v-2.629c-1.89-.08-3.366-2-3.366-4.367s1.477-4.287,3.366-4.369v-2.633a4.5,4.5,0,0,1,4.5-4.5h15.658v.129a3.676,3.676,0,0,0,.494,1.869h-16.152a2.5,2.5,0,0,0-2.5,2.5v14a2.5,2.5,0,0,0,2.5,2.5h1.741a1.006,1.006,0,0,1,1.009,1v2.432l4.544-3.244a.97.97,0,0,1,.576-.189h13.124a2.5,2.5,0,0,0,2.506-2.5v-9.441a3.524,3.524,0,0,0,1.118.189h.033a3.634,3.634,0,0,0,2.764-1.293,4.793,4.793,0,0,1,1.456,3.549,5.014,5.014,0,0,1-.982,3.041,3.23,3.23,0,0,1-2.391,1.334v2.621a4.507,4.507,0,0,1-4.5,4.5h-12.806l-5.858,4.184a1.021,1.021,0,0,1-.582.191A1.007,1.007,0,0,1-9736.837-26950.139Zm1.334-10.389a1.876,1.876,0,0,1-1.876-1.877v-7.869a1.876,1.876,0,0,1,1.876-1.877h15.739a1.876,1.876,0,0,1,1.876,1.877v7.869a1.876,1.876,0,0,1-1.876,1.877Zm10.931-5.811a1.752,1.752,0,0,0,1.754,1.746,1.751,1.751,0,0,0,1.747-1.746,1.754,1.754,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9724.572-26966.338Zm-9.617,0a1.752,1.752,0,0,0,1.748,1.746,1.751,1.751,0,0,0,1.747-1.746,1.755,1.755,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9734.189-26966.338Zm20.1-5.277-.453-1.551a4.433,4.433,0,0,0-2.946-3.006l-1.537-.467a.649.649,0,0,1-.447-.611.524.524,0,0,1,.021-.148.616.616,0,0,1,.217-.346.624.624,0,0,1,.217-.115l.284-.088,1.232-.365a4.417,4.417,0,0,0,2.96-3.02l.46-1.551a.625.625,0,0,1,.42-.434v.006a.538.538,0,0,1,.183-.033.574.574,0,0,1,.292.08.581.581,0,0,1,.3.381l.46,1.557a4.422,4.422,0,0,0,2.96,3.014l1.171.346.346.107a.647.647,0,0,1,.454.609.641.641,0,0,1-.447.611l-1.537.467a4.434,4.434,0,0,0-2.946,3.006l-.453,1.551a.631.631,0,0,1-.6.461A.636.636,0,0,1-9714.089-26971.615Zm-4.571-7.34-.183-.623a2.7,2.7,0,0,0-1.829-1.83l-.623-.189a.29.29,0,0,1-.2-.277.284.284,0,0,1,.2-.277l.61-.184a2.7,2.7,0,0,0,1.842-1.842l.183-.615a.32.32,0,0,1,.2-.2.327.327,0,0,1,.224.027.275.275,0,0,1,.143.17l.183.615a2.713,2.713,0,0,0,1.842,1.842l.609.184a.289.289,0,0,1,.21.277.3.3,0,0,1-.21.277l-.257.076-.366.113a2.725,2.725,0,0,0-1.828,1.83l-.183.623a.293.293,0,0,1-.278.2A.3.3,0,0,1-9718.66-26978.955Z" transform="translate(-8805.37 22282.029)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#ffcfd1;}.b{fill:#fff;opacity:0;}.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f5222d"/><stop offset="1" stop-color="#a8071a"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18558 4829)"><rect class="b" width="42" height="42" transform="translate(-18553 -4708)"/><path class="c" d="M-9520.252-26774.373h-17.5a8.261,8.261,0,0,1-8.248-8.254v-8.746a8.261,8.261,0,0,1,8.248-8.256h7.75v-2.582a2.5,2.5,0,0,1-1.5-2.287,2.506,2.506,0,0,1,2.5-2.5,2.5,2.5,0,0,1,2.5,2.5,2.515,2.515,0,0,1-1.5,2.293v2.576h2.752a1.254,1.254,0,0,1,1.251,1.252,1.254,1.254,0,0,1-1.251,1.252h-12.5a5.758,5.758,0,0,0-5.752,5.752v8.746a5.758,5.758,0,0,0,5.752,5.752h17.5a5.758,5.758,0,0,0,5.752-5.752v-5.746a1.252,1.252,0,0,1,1.251-1.25,1.252,1.252,0,0,1,1.252,1.25v5.746A8.264,8.264,0,0,1-9520.252-26774.373Zm-2.624-6.25h-12.251a5.506,5.506,0,0,1-5.5-5.5,5.5,5.5,0,0,1,5.5-5.5h12.251a5.507,5.507,0,0,1,5.5,5.5A5.509,5.509,0,0,1-9522.876-26780.623Zm-.989-7.812a.992.992,0,0,0-.706.291l-1.312,1.313a1,1,0,0,0-.289.707.985.985,0,0,0,.289.705l1.313,1.313a1,1,0,0,0,.706.3,1,1,0,0,0,.706-.3.988.988,0,0,0,.293-.707.987.987,0,0,0-.293-.705l-.605-.605.605-.605a.988.988,0,0,0,.293-.707.988.988,0,0,0-.293-.707A.988.988,0,0,0-9523.865-26788.436Zm-10.388.561a1.751,1.751,0,0,0-1.749,1.75,1.75,1.75,0,0,0,1.749,1.748,1.75,1.75,0,0,0,1.749-1.748A1.751,1.751,0,0,0-9534.253-26787.875Zm19.262-3.531a.587.587,0,0,1-.552-.4l-1.5-4.568-4.555-1.447a.593.593,0,0,1-.4-.551.577.577,0,0,1,.4-.553l4.5-1.514,1.419-4.5a.59.59,0,0,1,.557-.412.609.609,0,0,1,.17.027.569.569,0,0,1,.377.377l1.5,4.568,4.7,1.668a.579.579,0,0,1,.384.559.59.59,0,0,1-.417.545l-4.6,1.293-1.426,4.5A.572.572,0,0,1-9514.991-26791.406Z" transform="translate(-9002.999 22102.623)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="1080" viewBox="0 0 1920 1080"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 3840 2160"><image width="3840" height="2160" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 1.7 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="53" height="53" viewBox="0 0 53 53"><defs><style>.a{fill:#d4e9ff;stroke:#55a6fe;stroke-dasharray:4;}.b{fill:#fff;opacity:0;}.c{fill:url(#a);}</style><linearGradient id="a" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#0077fb"/><stop offset="1" stop-color="#004bb5"/></linearGradient></defs><g transform="translate(0.5 -109.5)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 110)"/><g transform="translate(6.5 116.5)"><rect class="b" width="39" height="39"/><path class="c" d="M20.72,28.846a8.938,8.938,0,0,1-7.044-14.437c.01-.014.02-.025.029-.037s.026-.035.04-.051l.02-.025.017-.02.012-.014c.01-.012.021-.023.03-.037l.015-.018a.179.179,0,0,0,.021-.025l.011-.012a.139.139,0,0,1,.011-.012l.064-.078.026-.031A.221.221,0,0,0,14,14.021a8.936,8.936,0,0,1,12.315-1.082c.093.072.181.146.279.234,0,0,0,0,.008.006.023.021.048.041.07.063a.393.393,0,0,1,.037.033c.015.012.028.025.041.037l.016.016a.055.055,0,0,1,.013.01l.014.012.014.012a.043.043,0,0,0,.008.01l0,0a8.964,8.964,0,0,1,2.719,5.055l0,.014c0,.031.01.061.015.09l0,.016,0,.016c0,.021.007.045.011.066l0,.018v0a.04.04,0,0,1,0,.01l0,.016,0,.018,0,.016c0,.018,0,.035.006.053a.171.171,0,0,1,0,.031c.011.078.02.158.026.238l.008.07v.018c0,.016,0,.029,0,.045a.106.106,0,0,0,0,.018.108.108,0,0,1,0,.018.28.28,0,0,0,0,.035l0,.051v.006c0,.021,0,.045,0,.064s0,.02,0,.029a.064.064,0,0,1,0,.014v.014c0,.021,0,.041,0,.063v.014c0,.01,0,.02,0,.029v.018c0,.025,0,.049,0,.074s0,.033,0,.049a.131.131,0,0,0,0,.02V19.7c0,.016,0,.027,0,.043v.041c0,.041,0,.082,0,.123A8.947,8.947,0,0,1,20.72,28.846Zm-3.574-9.953a1.016,1.016,0,0,0,0,2.031H19.7v2.563a1.016,1.016,0,0,0,2.031,0V20.924h2.563a1.016,1.016,0,0,0,0-2.031H21.73V16.334a1.016,1.016,0,0,0-2.031,0v2.559Zm-6.872,9.547H2.726A2.731,2.731,0,0,1,0,25.709V18.166a2.728,2.728,0,0,1,2.726-2.725h7.548a2.736,2.736,0,0,1,1.336.35A10.015,10.015,0,0,0,12.954,26.2,2.727,2.727,0,0,1,10.273,28.439ZM2.726,17.877a.292.292,0,0,0-.289.289v7.543A.293.293,0,0,0,2.726,26h7.548a.292.292,0,0,0,.289-.295V18.166a.292.292,0,0,0-.289-.289ZM10.273,13H2.726A2.731,2.731,0,0,1,0,10.273V2.73A2.731,2.731,0,0,1,2.726,0h7.548A2.731,2.731,0,0,1,13,2.73v7.543A2.731,2.731,0,0,1,10.273,13Zm17.09-.559v0a9.929,9.929,0,0,0-3.091-1.881H25.71A.288.288,0,0,0,26,10.273V2.73a.288.288,0,0,0-.288-.289H18.166a.286.286,0,0,0-.289.289v7.543c0,.014,0,.027,0,.049a9.841,9.841,0,0,0-2.246.979,2.737,2.737,0,0,1-.2-1.027V2.73A2.734,2.734,0,0,1,18.166,0H25.71a2.733,2.733,0,0,1,2.729,2.73v7.543a2.709,2.709,0,0,1-1.075,2.17Z" transform="translate(5.281 5.278)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.6 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#aad2ff;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#0077fb"/><stop offset="1" stop-color="#004bb5"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(2.236 118.236)"><path class="b" d="M9204.336-22218.762a6.4,6.4,0,0,1-2.489-.691,6.242,6.242,0,0,1-2-1.615,6.363,6.363,0,0,1-1.206-2.283,6.357,6.357,0,0,1-.246-1.863c-.047-.033-.094-.066-.139-.1a6.4,6.4,0,0,1-2.272-3.4,6.418,6.418,0,0,1,.268-4.076,6.336,6.336,0,0,1,1.233-1.912,6.383,6.383,0,0,1-.4-1.973,6.41,6.41,0,0,1,.53-2.809,6.441,6.441,0,0,1,1.7-2.289,6.424,6.424,0,0,1,1.751-1.057,4.969,4.969,0,0,1,.343-1.289,4.965,4.965,0,0,1,1.334-1.859,5.038,5.038,0,0,1,2.016-1.082,5.037,5.037,0,0,1,2.289-.074,5.024,5.024,0,0,1,2.089.943,4.947,4.947,0,0,1,.871.861,5.147,5.147,0,0,1,.876-.861,5,5,0,0,1,2.083-.943,5.035,5.035,0,0,1,2.289.074,5.06,5.06,0,0,1,2.021,1.082,5.031,5.031,0,0,1,1.334,1.859,5.008,5.008,0,0,1,.343,1.289,6.424,6.424,0,0,1,1.751,1.057,6.441,6.441,0,0,1,1.7,2.289,6.405,6.405,0,0,1,.524,2.809,6.434,6.434,0,0,1-.4,1.973,6.315,6.315,0,0,1,1.234,1.912,6.418,6.418,0,0,1,.268,4.076,6.4,6.4,0,0,1-2.272,3.4l-.143.105a6.214,6.214,0,0,1-.248,1.859,6.26,6.26,0,0,1-1.2,2.283,6.271,6.271,0,0,1-2.01,1.615,6.354,6.354,0,0,1-2.485.691c-.14.006-.278.012-.418.012a6.213,6.213,0,0,1-2.139-.375,6.394,6.394,0,0,1-2.2-1.34,6.4,6.4,0,0,1-.915-1.066,6.415,6.415,0,0,1-.91,1.066,6.427,6.427,0,0,1-2.206,1.34,6.283,6.283,0,0,1-2.143.377C9204.609-22218.748,9204.473-22218.752,9204.336-22218.762Zm6.768-6.342a4.232,4.232,0,0,0,.346,1.652,4.123,4.123,0,0,0,.972,1.379,4.116,4.116,0,0,0,1.44.877,4.062,4.062,0,0,0,1.67.234,4.159,4.159,0,0,0,1.63-.447,4.159,4.159,0,0,0,1.313-1.061,4.227,4.227,0,0,0,.787-1.49c.02-.07.037-.139.054-.209a6.32,6.32,0,0,1-1.422.164,1.1,1.1,0,0,1-1.1-1.1,1.1,1.1,0,0,1,1.1-1.1,4.178,4.178,0,0,0,2.529-.859,4.138,4.138,0,0,0,1.485-2.221,4.216,4.216,0,0,0-.173-2.67,4.2,4.2,0,0,0-1.765-2.01,1.1,1.1,0,0,1-.4-1.5,1.1,1.1,0,0,1,1.063-.543,4.16,4.16,0,0,0,.1-.758,4.249,4.249,0,0,0-.346-1.838,4.156,4.156,0,0,0-1.117-1.5,4.078,4.078,0,0,0-.569-.408,4.928,4.928,0,0,1-.385.838,1.1,1.1,0,0,1-.955.553,1.08,1.08,0,0,1-.547-.15,1.093,1.093,0,0,1-.4-1.5,2.906,2.906,0,0,0,.374-1.229,1.022,1.022,0,0,1,.006-.145,2.841,2.841,0,0,0-.218-1.133,2.836,2.836,0,0,0-.754-1.051,2.794,2.794,0,0,0-1.139-.607,2.8,2.8,0,0,0-1.29-.045,2.782,2.782,0,0,0-1.173.535,2.84,2.84,0,0,0-.82.994,2.912,2.912,0,0,0-.3,1.262v5.254a4.426,4.426,0,0,0,.877,2.625,4.4,4.4,0,0,0,2.277,1.58,1.1,1.1,0,0,1,.748,1.361,1.1,1.1,0,0,1-1.367.748,6.6,6.6,0,0,1-2.535-1.41v6.928Zm-10.352,1.145a4.119,4.119,0,0,0,.787,1.49,4.148,4.148,0,0,0,1.313,1.061,4.105,4.105,0,0,0,1.624.447,4.076,4.076,0,0,0,1.676-.234,4.125,4.125,0,0,0,1.44-.877,4.208,4.208,0,0,0,.972-1.379,4.226,4.226,0,0,0,.34-1.652v-6.924a6.628,6.628,0,0,1-2.534,1.406,1.117,1.117,0,0,1-.308.045,1.1,1.1,0,0,1-1.055-.793,1.093,1.093,0,0,1,.748-1.361,4.393,4.393,0,0,0,2.272-1.58,4.354,4.354,0,0,0,.876-2.625v-5.254a2.906,2.906,0,0,0-.29-1.262,2.84,2.84,0,0,0-.82-.994,2.778,2.778,0,0,0-1.179-.535,2.8,2.8,0,0,0-1.29.045,2.832,2.832,0,0,0-1.139.607,2.821,2.821,0,0,0-.748,1.051,2.819,2.819,0,0,0-.212,1.271,2.821,2.821,0,0,0,.374,1.234,1.1,1.1,0,0,1-.4,1.5,1.1,1.1,0,0,1-1.5-.4,5.009,5.009,0,0,1-.386-.838,4.127,4.127,0,0,0-.568.408,4.156,4.156,0,0,0-1.117,1.5,4.249,4.249,0,0,0-.346,1.838,4.246,4.246,0,0,0,.1.758,1.106,1.106,0,0,1,1.064.543,1.1,1.1,0,0,1-.4,1.5,4.2,4.2,0,0,0-1.765,2.01,4.216,4.216,0,0,0-.173,2.67,4.138,4.138,0,0,0,1.485,2.221,4.178,4.178,0,0,0,2.529.859,1.1,1.1,0,0,1,1.1,1.1,1.1,1.1,0,0,1-1.1,1.1,6.32,6.32,0,0,1-1.422-.164C9200.714-22224.1,9200.732-22224.029,9200.752-22223.959Z" transform="translate(-9186.242 22256.754)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#aad2ff;}.b{opacity:0;}.b,.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#0077fb"/><stop offset="1" stop-color="#004bb5"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18559 4825)"><rect class="b" width="42" height="42" transform="translate(-18554 -4704)"/><path class="c" d="M-9736.837-26950.139a1.008,1.008,0,0,1-.542-.889v-3.371h-.752a4.506,4.506,0,0,1-4.5-4.5v-2.629c-1.89-.08-3.366-2-3.366-4.367s1.477-4.287,3.366-4.369v-2.633a4.5,4.5,0,0,1,4.5-4.5h15.658v.129a3.676,3.676,0,0,0,.494,1.869h-16.152a2.5,2.5,0,0,0-2.5,2.5v14a2.5,2.5,0,0,0,2.5,2.5h1.741a1.006,1.006,0,0,1,1.009,1v2.432l4.544-3.244a.97.97,0,0,1,.576-.189h13.124a2.5,2.5,0,0,0,2.506-2.5v-9.441a3.524,3.524,0,0,0,1.118.189h.033a3.634,3.634,0,0,0,2.764-1.293,4.793,4.793,0,0,1,1.456,3.549,5.014,5.014,0,0,1-.982,3.041,3.23,3.23,0,0,1-2.391,1.334v2.621a4.507,4.507,0,0,1-4.5,4.5h-12.806l-5.858,4.184a1.021,1.021,0,0,1-.582.191A1.007,1.007,0,0,1-9736.837-26950.139Zm1.334-10.389a1.876,1.876,0,0,1-1.876-1.877v-7.869a1.876,1.876,0,0,1,1.876-1.877h15.739a1.876,1.876,0,0,1,1.876,1.877v7.869a1.876,1.876,0,0,1-1.876,1.877Zm10.931-5.811a1.752,1.752,0,0,0,1.754,1.746,1.751,1.751,0,0,0,1.747-1.746,1.754,1.754,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9724.572-26966.338Zm-9.617,0a1.752,1.752,0,0,0,1.748,1.746,1.751,1.751,0,0,0,1.747-1.746,1.755,1.755,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9734.189-26966.338Zm20.1-5.277-.453-1.551a4.433,4.433,0,0,0-2.946-3.006l-1.537-.467a.649.649,0,0,1-.447-.611.524.524,0,0,1,.021-.148.616.616,0,0,1,.217-.346.624.624,0,0,1,.217-.115l.284-.088,1.232-.365a4.417,4.417,0,0,0,2.96-3.02l.46-1.551a.625.625,0,0,1,.42-.434v.006a.538.538,0,0,1,.183-.033.574.574,0,0,1,.292.08.581.581,0,0,1,.3.381l.46,1.557a4.422,4.422,0,0,0,2.96,3.014l1.171.346.346.107a.647.647,0,0,1,.454.609.641.641,0,0,1-.447.611l-1.537.467a4.434,4.434,0,0,0-2.946,3.006l-.453,1.551a.631.631,0,0,1-.6.461A.636.636,0,0,1-9714.089-26971.615Zm-4.571-7.34-.183-.623a2.7,2.7,0,0,0-1.829-1.83l-.623-.189a.29.29,0,0,1-.2-.277.284.284,0,0,1,.2-.277l.61-.184a2.7,2.7,0,0,0,1.842-1.842l.183-.615a.32.32,0,0,1,.2-.2.327.327,0,0,1,.224.027.275.275,0,0,1,.143.17l.183.615a2.713,2.713,0,0,0,1.842,1.842l.609.184a.289.289,0,0,1,.21.277.3.3,0,0,1-.21.277l-.257.076-.366.113a2.725,2.725,0,0,0-1.828,1.83l-.183.623a.293.293,0,0,1-.278.2A.3.3,0,0,1-9718.66-26978.955Z" transform="translate(-8805.37 22282.029)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="52" height="52" viewBox="0 0 52 52"><defs><style>.a{fill:#aad2ff;}.b{fill:#fff;opacity:0;}.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#0077fb"/><stop offset="1" stop-color="#004bb5"/></linearGradient></defs><g transform="translate(0 -116.002)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18558 4829)"><rect class="b" width="42" height="42" transform="translate(-18553 -4708)"/><path class="c" d="M-9520.252-26774.373h-17.5a8.261,8.261,0,0,1-8.248-8.254v-8.746a8.261,8.261,0,0,1,8.248-8.256h7.75v-2.582a2.5,2.5,0,0,1-1.5-2.287,2.506,2.506,0,0,1,2.5-2.5,2.5,2.5,0,0,1,2.5,2.5,2.515,2.515,0,0,1-1.5,2.293v2.576h2.752a1.254,1.254,0,0,1,1.251,1.252,1.254,1.254,0,0,1-1.251,1.252h-12.5a5.758,5.758,0,0,0-5.752,5.752v8.746a5.758,5.758,0,0,0,5.752,5.752h17.5a5.758,5.758,0,0,0,5.752-5.752v-5.746a1.252,1.252,0,0,1,1.251-1.25,1.252,1.252,0,0,1,1.252,1.25v5.746A8.264,8.264,0,0,1-9520.252-26774.373Zm-2.624-6.25h-12.251a5.506,5.506,0,0,1-5.5-5.5,5.5,5.5,0,0,1,5.5-5.5h12.251a5.507,5.507,0,0,1,5.5,5.5A5.509,5.509,0,0,1-9522.876-26780.623Zm-.989-7.812a.992.992,0,0,0-.706.291l-1.312,1.313a1,1,0,0,0-.289.707.985.985,0,0,0,.289.705l1.313,1.313a1,1,0,0,0,.706.3,1,1,0,0,0,.706-.3.988.988,0,0,0,.293-.707.987.987,0,0,0-.293-.705l-.605-.605.605-.605a.988.988,0,0,0,.293-.707.988.988,0,0,0-.293-.707A.988.988,0,0,0-9523.865-26788.436Zm-10.388.561a1.751,1.751,0,0,0-1.749,1.75,1.75,1.75,0,0,0,1.749,1.748,1.75,1.75,0,0,0,1.749-1.748A1.751,1.751,0,0,0-9534.253-26787.875Zm19.262-3.531a.587.587,0,0,1-.552-.4l-1.5-4.568-4.555-1.447a.593.593,0,0,1-.4-.551.577.577,0,0,1,.4-.553l4.5-1.514,1.419-4.5a.59.59,0,0,1,.557-.412.609.609,0,0,1,.17.027.569.569,0,0,1,.377.377l1.5,4.568,4.7,1.668a.579.579,0,0,1,.384.559.59.59,0,0,1-.417.545l-4.6,1.293-1.426,4.5A.572.572,0,0,1-9514.991-26791.406Z" transform="translate(-9002.999 22102.623)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.0 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="1080" viewBox="0 0 1920 1080"><image width="1920" height="1080" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAADwAAAAhwCAYAAACQvstyAAAgAElEQVR4nOzdi3KjOrYA0JCZ///huR1uJTGOLSzrgcRzrapzOoltwCCEkMTew9fXOH4AcHnTxWC4/3D1PcKZaOwAcCZhM811bluazQDnoDsEAACgj7D/crrvSvVruj+DHWjVYRKrCNhG4XFt3W+21rhW7vUGAOgn1X4ovU5rRnIF9/Mich/lPAA4l5x+l/8bPz7+a2ITAI+iNw5wYIozAGfmOrexRh3szY9jbYePiVjASdRO8EtVg7HqdWk9rroFAAB6ad3dk3v/E1tPq34w/aKwY61P0FYdL2HHTuz32OdK1zfZa4WV6uhq3GE1palZe3e4XgDAfrlOw5xpOwCEvvtU/iu1AQAfj+MWQmBeisMMAMfj+r0z04SVvUTaDAtIagJT6fKWSk2kiq1fvxVQqHZeZuxzqeoVAACAvPum0vsp/aGwoaUBJie1HSi9Igakfl+6/r1XXGFHWGJ7WwWO8OAvAFzP3uLCbMV44jXkBppOGYIFKD8A5/aunh9u14/vfz9X3CYAAAAAAAAAAAAAAAAAAOCN7weA/yskBACPwshB94hDQmOeisMJANDGPWPJwlSQtQl6sz+w9wZgbP/ptwJWEkuY7v4ZAACgTqpbx/0WHFAqtXdorVTftam1cpd70QqrWfe8Ch8AuLiF00k4iNrjK+MvADGPc5dkAAYAAAAAAAAAAAAAAAAAgB35r5AiALxzD2gaiWxaGqizNNJzr0CtAADQUqodmyuaUCC3Ibz3jASp7crNFLFVBofYge19Y1S6vNr9o38Qik+fVtXR0m563fwAAECo9f3KWp8DOijN3JuS+7m1KoJe6zlrRZb6Xo06mMYxb3UAAFdx1nZRq2kXKWtPg6j9PsWfk/kXgAwyAAMAAAAAAAAAAAAAAAAAwI7818EAIEcYaegeILYwYmdtJh2RjQAAOIIxaMA2ywScGzL1qhkJYlpn2q3NzBt+rlXGjdj3K81U7IYLdkMmYAAA4KhaJRYFOihNycU1tcr8q7gBAJza0nkwobDd2HqcM3eaRG37VcZfANYgAzAAAAAAAAAAAAAAAAAAAOyIDMAAVLkHiJ0iERVmAi4lMigAAEfSKhMwlVpn/q3Vej17+V7A7kjkAwAApKzdP+U+BVYQ9EMnSdXNg1imtdrrxT3zr3IFAHBqvTPlHnU6R4zMvwC0IAMwAAAAAAAAAAAAAAAAAADsiAzAACwSRiaaiOgJAAAVGRgCMqVU2ssOix33Mfg3TK3ggAMAAAAbK+2eWNgNBtQI+xOdgBRonolMvzYAANwNMv4C0JAMwAAAAAAAAAAAAAAAAAAAsCP/HW7B1wRgW4cIHsDZzTICj0//wKWE5V47AACu594euP0wLM0ELEPsseQep9bvK3X28pTKxJx6H2xA4h4AAKDW1rf5uq3YtbMXUCfgpZUe/iH4t9ZoXhAAcGP4lSsL588r/0Brtffdi+/7HcnNDA/7/78X/P4AAJswgRsAAAAAAAAAOAsTgQEAAAD6+u+U/deDKOvQ4QVcTiRDmfqQK1P+AeB6puv/Z6Nvrj0BDaQyasf+riOVHXN9AAAAYhmXSu8X3F9wCLkpxhRoLiRV3MPMZEtPD6cXABCjncAVhO3rifIP7IX66LimYzfKAAwAsB4ZgAEA7QEAAAAAAODoTCAGAAAAWMd/W0VyI09qgm/pcTBhGDiKIbjeDOPz73BmYTnPjrgLABxOsn0bPAG89+v+1u117SKayC3IrQq8Bj8NCRwBAADkWuu2losrzbi7dkZeBfjUcjOch8Vu6Xy8WHHeS/958XYs7Gi6Z59xvgHA5cQu/8axuJIw46/yD/Sy9LZ7af3ktn97w8Nx+LzyjgAAAAAAAAAAAAAAAAAAgL35rxQC+7C3J+MVC6CXMPLRRGRQzqw08m5u4GwAYD2t7pPHhx+GBQscbp87Wjtau4hTKy3YCjQdhPWsYgYAANflfoBV5N6Amg9AR60TTcc+t9f5fbmm/bT4+uB8BoDLkfkXHtrTCj4QkbpdLq0+SufZhZbOG1m6ftqSARgAAABgA6MOMgAAAAAAAAAAAAAi/mvHHFvrCAGh3ssHCDMCywTMmYXXTQnCAOA4Wl+Hx2mZ4+3ni2QCXrqZuZ/XbqKrpQVZAaVC7X2h+0kAADiv1t1Bhml5kntDmUoFUluwpBi5tNJxdN5rlalsGoew3wHg/GT8hfn8duUfiHGfzBpkAAZgVwY3SQAAXIQMwAAAAAAAAAAAAADEzDIApwIoCrB4LKUReBxXOI+jZXi5X1+mSEkih8KM8+G9teq7sH51XCAu9zw56vm09nan7uNab08sc32r+rbV8s6QQGL8+NuQ6gj8hV8otv/Pfl3bKnFruF5Bjy4idl5KycoKwuKn2AEAwHnk9rfCIrmZf3sxAHcJDnNfYcayWmH/Uu18xNR4ROnnc8XWUzs/ttX4Uulyeo9rmf8A+xU7P9eaH7B0OaVS14dW14Xcz591vgsQN83b0b8CpJRe/3PbIeH7lt5Pa6ecgwzAAOyKDMAAAAAAAAAAAAAAAADA1c0yAKee7Pbk9zJ7ybTQ6jiKLAv7d9QML7PMZzICc0IiAPbVOiJkLHFbSiqyEpxZbjk/6vmw9nZvtZ961X+5kezC5a11P7uW0kj5Mff90ygT8NH1Or615ZeDWLuBLjU0AAAAO6AfgyelE4F6p8jk0HK7vxSXvpZmSBwz5+uUjs/njiO1yvyb+nts/aWfz1WbKaoX5x8cV+51NPW+3HHrpfVXaXMy9++l29FqnH7t+rP7PLTIhdAwJlcg8y+cT+95cbXtpNh2LZ2XybnNHgAGAAAAAAAAAAAAAAAAOCsP0gFwBMO/f+NvkLaTXbmWRhzai71HONTgAdaWG1kUjiC7HAvpA/XCUFlbpbpcuh17TdF51tShsKFh+q/yvBqDH7SbjyXVD6S6PZjSjr3Y+7dux7BLR29GAgAA+UozEe49YxUHk1vAFKRVHDVTHeu6Z85d2CH0PT9nfJinc6ejCQDOI7OB6fLPGd3Ltcy/wE2r+RW10/711xAabuXi39fHx6e9AwAAALAfOvMAAAAAAIAtGasAAOAKBg//AnAA/z3rQWrVAbX1E/V770hLbZ/GENBaGKF0FmkUDiQ7IVjuG6V2grnwfOh1fpRGvu6dsk0kbjiscYrcdjuPSyP035sNkfaDBB37VFtNq+4PojS1sxCfNJQqTuoNAADYv+zxJGhBQdu1Xhlo1DMn0yDz7+8PQZnQkQSszTwoaC93vPL9n+HQpnk4yjcQWivzb+37ubbTPgAMwDUYiAIA4Gw8nAUAAAAAAGzh4flfAAA4DXNvADgyDwAn6Mha5mz7L/agYe4DiLkJXwoDLGXvZw3XbW09if9s5STMbDbcvqB6my2sVu5KMwHXfj53O1J675i9V1ixSKSpC0LtfpMpbl9i+7/2uCw9nr3Lw1HKW209uDQDc2w5pQ3EVITj0gjIra4HvfdnKPyeezmerUzt2oeIo2PF6nIvCy4X+5B7HEqbgWv3I3h4PdDqwC59f2uXP7Abq8x4UFvMHG4AAFjfWrd9p+8Xyh0vq+0AadXPeDQ6FLuoHS6AV+Wmtj9nyvy7uHydpWOp9fdofd056kQwFRg1rlJutsqEkpoYvbatriNrzwtIaTUPIndie+XHWzMuRQ/3cnWwzL+508RCa32/2umxtcslb7/FlE43rL3dqC2XW01jhCPxADAAh6bBBgDAmdU8/AsAAAAAAJBrNO8GAICTM/cGgCPzADA8SD1IWBtRpFUCrlhElNKEkBqwx7Q0Ik7tg7JHKTdDsIGjkQl2qFmC1qUndC+tMtfmbu9aIcxaNQBKUy/WFhj1H8TVZo5tfV7V3nCk6qFWNx659XLp/mydEWOt+m5pRpBcsf0bbkepKYJpq8j9HEqvfozS6lM/BDR0O6FKz6/S/kMAAGA9ud1qrbvfqh31hr91qpO9ZQhjF0pPj9r3t6Y/4Nju88cq658x+HfxxLmz1IOtv8fSE33pOGIvKhBoZ6vx77Xmk5UOaNQuL3d9W2U8rr3/2LrB2JnbKGqkTuOpfXy08lU6zTT3fWs1b2vXk5qWtnR5pc5WL9XO82k9LTy2nqXclnAFn44yAAAAwH7ppAQAAAAAAHoxDgEAwFkMHioH4ISGf//G3ySJrnJcwNJIFJPcwEup9y19PVzObiL+ZpIJ6FduILFW+2tpOTnKcbsHqDNKcWi5hy+3Pj1scSi9gAAApzI8RiatjeAvAzA7FGvW5iYiv3p/wmqWhtR1oPq47d/S60Lp/bLDBwAA/eSO/7eeDzDL8Fja8N/7/V5pxq/cjgguxeHnCJZm/p18jx+MZ55fU3udi31eBQHwrHZiXu2AoHq4jdRA7dEmpDdiXGzfUv0oQ/CHs2Zwbd28Xbpe8zjW1at6ru0my5334/INdYbb+fPv6+Pjv/YhAGd2+Ac/AQC4PM/QAQAAAAAAPZhPAwDAmZhbA8AZeQCYS2nVYdl68nVsu3K3t/R7Lc2M2ep7HyWD7NkyJ6eOd2lA5HC5e3H/nlMkJxnPDmVpvVb6+mpqT5yFkcc9NATAru09YstWIQmD/fITgX/4+Pgcf18rva4P4fKabSjUK70v1Z49GAesr9v+rb3fc3gAAGC/dt9vc/QbitYDiyJS70qrcdFYJu6P4O+wleGjbqzgqRxPBXncuEyvfYKVVhQmXAD0UVvfa5i1kZtC0v5lx+6Zfw+W8bc0k+pSSzPChr+rHvpq/TxPbnlLvb90+coHtLine truncated

Before

Width:  |  Height:  |  Size: 1.9 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="582" height="667" viewBox="0 0 582 667"><image width="582" height="667" xlink:href="data:image/png;base64,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VkILine truncated

Before

Width:  |  Height:  |  Size: 608 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" width="1" height="1" patternTransform="matrix(-1, 0, 0, 1, 278, 0)" viewBox="0 0 139 765"><image preserveAspectRatio="none" width="139" height="765" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 50 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><image width="139" height="765" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="727" height="727" viewBox="0 0 727 727"><defs><style>.a{fill:url(#a);}.b{fill:url(#d);}.c,.d,.f{fill:none;}.c{stroke:rgba(32,194,255,0);stroke-width:8px;}.d{stroke:rgba(32,194,255,0.15);stroke-width:5px;stroke-dasharray:7 5;}.e{stroke:none;}.g{filter:url(#e);}.h{filter:url(#b);}</style><linearGradient id="a" x1="0.351" y1="0.016" x2="0.065" y2="0.243" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#1ec6fe"/><stop offset="1" stop-color="#3279ff"/></linearGradient><filter id="b" x="88.068" y="60.324" width="217.004" height="181.59" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="c"/><feFlood flood-color="#1a9cff" flood-opacity="0.8"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><linearGradient id="d" x1="0.025" y1="0.971" x2="0.971" y2="0.034" xlink:href="#a"/><filter id="e" x="424.041" y="484.359" width="215.309" height="181.689" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="f"/><feFlood flood-color="#1a9cff" flood-opacity="0.8"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter></defs><g transform="translate(4 4)"><g transform="translate(-126.998 -127.002)"><g class="h" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="a" d="M18115.566-21172.494q4.919-8.443,10.389-16.543a294.531,294.531,0,0,1,35.713-43.289,294.545,294.545,0,0,1,43.293-35.717,292.5,292.5,0,0,1,49.682-26.969,290.614,290.614,0,0,1,31.271-11.162l1.656,5.506a288.092,288.092,0,0,0-166.973,131.084Z" transform="translate(-18005 21389)"/></g><g class="g" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="b" d="M18451.539-20750.967a288.209,288.209,0,0,0,165.279-131.172l5.029,2.92q-5.1,8.815-10.8,17.258a294.659,294.659,0,0,1-35.717,43.287,294.647,294.647,0,0,1-43.293,35.717,292.2,292.2,0,0,1-49.686,26.971,291.1,291.1,0,0,1-29.178,10.537Z" transform="translate(-18005 21389)"/></g><circle class="c" cx="359.5" cy="359.5" r="359.5" transform="translate(126.998 127.002)"/></g><g class="d" transform="translate(98 98)"><circle class="e" cx="261.5" cy="261.5" r="261.5"/><circle class="f" cx="261.5" cy="261.5" r="259"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="458" height="113.588" viewBox="0 0 458 113.588"><defs><style>.a{fill:url(#a);}.b{fill:#fff;}.c{filter:url(#d);}.d{filter:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f0feff"/><stop offset="1" stop-color="#c1e6ff"/></linearGradient><filter id="b" x="111.721" y="26.943" width="211.559" height="46.289" filterUnits="userSpaceOnUse"><feOffset dy="1" input="SourceAlpha"/><feGaussianBlur stdDeviation="3" result="c"/><feFlood flood-color="#00ffa2" flood-opacity="0.322"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><filter id="d" x="111.721" y="26.943" width="211.559" height="46.289" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="2" result="e"/><feFlood flood-color="#fff" result="f"/><feComposite operator="out" in="SourceGraphic" in2="e"/><feComposite operator="in" in="f"/><feComposite operator="in" in2="SourceGraphic"/></filter></defs><g transform="translate(-731 -564.412)"><image width="458" height="113.588" transform="translate(731 564.412)" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 813 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#2bbaff"/><stop offset="0.498" stop-color="#1a8cfd"/><stop offset="1" stop-color="#006aef"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M110.023,105.37H98.2a1.721,1.721,0,0,1-1.716-1.716v-1.918h10.189a1.721,1.721,0,0,0,1.716-1.716V72.8a1.721,1.721,0,0,0-1.716-1.716H98.2V67.437A3.444,3.444,0,0,0,94.76,64H87.83a3.444,3.444,0,0,0-3.437,3.437v3.652H75.625A1.721,1.721,0,0,0,73.91,72.8v27.21a1.721,1.721,0,0,0,1.716,1.716h10.49v1.918a1.721,1.721,0,0,1-1.716,1.716H72.3a1.721,1.721,0,0,0-1.716,1.716v10.1A1.721,1.721,0,0,0,72.3,118.9h37.724a1.721,1.721,0,0,0,1.716-1.716v-10.1A1.726,1.726,0,0,0,110.023,105.37Zm-8.406-19.1a3.437,3.437,0,1,1-3.437-3.437A3.436,3.436,0,0,1,101.616,86.266ZM87.83,67.437h6.924v3.646H87.83ZM81.121,86.266A3.437,3.437,0,1,1,84.558,89.7,3.436,3.436,0,0,1,81.121,86.266Zm32.48-7.089V93.355a1.716,1.716,0,0,1-3.431,0V79.177a1.716,1.716,0,0,1,3.431,0Zm5.122,3.548v6.881a1.716,1.716,0,0,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0ZM70.644,95.07a1.717,1.717,0,0,1-1.716-1.716V79.177a1.716,1.716,0,0,1,3.431,0V93.355A1.713,1.713,0,0,1,70.644,95.07ZM67.231,82.724v6.881a1.716,1.716,0,1,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0Zm0,0" transform="translate(-14540.154 22987.455)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1,48 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="188" height="241" viewBox="0 0 188 241" fill="none">
<defs>
<radialGradient id="surface" cx="0" cy="0" r="1" gradientTransform="translate(63 27) rotate(61) scale(148 156)" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFFFFF"/>
<stop offset=".2" stop-color="#FAFDFF"/>
<stop offset=".48" stop-color="#E4F2FF"/>
<stop offset=".72" stop-color="#A7D4FF"/>
<stop offset="1" stop-color="#3C9AF4"/>
</radialGradient>
<radialGradient id="inner-blue" cx="0" cy="0" r="1" gradientTransform="translate(94 101) rotate(90) scale(68 84)" gradientUnits="userSpaceOnUse">
<stop stop-color="#68B6FF" stop-opacity=".58"/>
<stop offset="1" stop-color="#1688F7" stop-opacity="0"/>
</radialGradient>
<linearGradient id="lower-blue" x1="94" y1="103" x2="94" y2="165" gradientUnits="userSpaceOnUse">
<stop stop-color="#4EA7FA" stop-opacity="0"/>
<stop offset="1" stop-color="#188AF4" stop-opacity=".72"/>
</linearGradient>
<linearGradient id="edge" x1="38" y1="10" x2="151" y2="160" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFFFFF" stop-opacity=".98"/>
<stop offset=".52" stop-color="#FFFFFF" stop-opacity=".86"/>
<stop offset="1" stop-color="#C6E8FF" stop-opacity=".9"/>
</linearGradient>
<filter id="glow" x="-13" y="-13" width="214" height="214" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="4.8"/>
</filter>
<filter id="shadow" x="18" y="162" width="152" height="49" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="7"/>
</filter>
<clipPath id="clip">
<circle cx="94" cy="82" r="81"/>
</clipPath>
</defs>
<ellipse cx="94" cy="188" rx="65" ry="9" fill="#147BD2" fill-opacity=".23" filter="url(#shadow)"/>
<circle cx="94" cy="82" r="82" fill="#5EBAFF" fill-opacity=".2" filter="url(#glow)"/>
<circle cx="94" cy="82" r="81" fill="url(#surface)"/>
<g clip-path="url(#clip)">
<ellipse cx="94" cy="106" rx="80" ry="61" fill="url(#inner-blue)"/>
<ellipse cx="94" cy="143" rx="91" ry="38" fill="url(#lower-blue)"/>
<ellipse cx="94" cy="151" rx="76" ry="14" fill="#FFFFFF" fill-opacity=".11"/>
<path d="M20 145C47 157 141 157 168 145" stroke="#FFFFFF" stroke-opacity=".28" stroke-width="1.2"/>
<path d="M31 160C55 168 133 168 157 160" stroke="#7CC4FF" stroke-opacity=".35" stroke-width="1.1"/>
<path d="M22 64C27 37 49 16 77 9" stroke="#FFFFFF" stroke-opacity=".42" stroke-width="8" stroke-linecap="round" filter="url(#glow)"/>
</g>
<circle cx="94" cy="82" r="81" stroke="url(#edge)" stroke-width="2"/>
<circle cx="94" cy="82" r="76" stroke="#FFFFFF" stroke-opacity=".24"/>
<path d="M19 70C24 39 49 13 81 5" stroke="#FFFFFF" stroke-opacity=".88" stroke-width="2" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.431" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#2bbaff"/><stop offset="0.498" stop-color="#1a8cfd"/><stop offset="1" stop-color="#006aef"/></linearGradient></defs><g transform="translate(-71.077 -67.746)"><g class="a" transform="translate(71.077 67.746)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M114.406,106.791a7.707,7.707,0,0,0-4.354,1.353L98.7,99.937a13.3,13.3,0,0,0,1.742-6.583c0-.421-.03-.842-.06-1.263L112,85.207a4.687,4.687,0,1,0-1.952-2.345L99.691,88.995a13.678,13.678,0,0,0-6.1-7.365l2.072-10.341c.15,0,.3.03.451.03a4.66,4.66,0,1,0-4.655-4.659,4.727,4.727,0,0,0,1.412,3.367l-2.1,10.462A13.479,13.479,0,0,0,80.05,81.87l-6.4-5.712A6.129,6.129,0,1,0,71.7,78.443L77.677,83.7a13.456,13.456,0,0,0,.691,19.991l-5.316,5.622a5.948,5.948,0,0,0-3.394-1.022,6.163,6.163,0,1,0,6.156,6.162,6.343,6.343,0,0,0-.721-2.916l5.826-6.193a13.464,13.464,0,0,0,16.1-2.946l11.022,7.966a7.77,7.77,0,0,0-1.2,4.118,7.658,7.658,0,1,0,15.316,0A7.817,7.817,0,0,0,114.406,106.791Zm0,0" transform="translate(13 9.671)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.337" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#2bbaff"/><stop offset="0.498" stop-color="#1a8cfd"/><stop offset="1" stop-color="#006aef"/></linearGradient></defs><g transform="translate(-204.426 -230.797)"><rect class="a" width="68" height="68" transform="translate(204.426 230.797)"/><g transform="translate(209.658 232.191)"><path class="b" d="M25.52,64.045c-1.725-.852-8.6-4.486-10.846-5.656-2.309-1.207-3.3-1.01-5.09.146L6.346,60.67,0,46.383s6.887-3.254,10.033-4.508C15,39.885,17.273,41.6,20.115,43.4c1.209.762,5.131,3.664,5.131,3.664a17.886,17.886,0,0,0,7.783,2.316c5.928,0,6.975.344,6.975,2.266,0,2.113-3.859,2.266-3.883,2.266H26.605c-3.236,0-7.766-1.893-7.766-1.893s3.846,4.156,7.766,4.156h9.547c2.105-.047,6.1-1.047,6.1-4.537,0-4.529-4.066-4.529-9.219-4.529a5.2,5.2,0,0,1-1.127-.145c.2-.1.4-.207.639-.35.9-.523,2.145-1.27,3.535-2.158,3.67-2.3,5.555-2.592,7.387-.152a5.718,5.718,0,0,1,4.248-1.678c1.551,0,2.865,1.039,2.494,2.719,3.975-2.377,5.936-1.42,6.809-.266,1.156,1.527.373,3.109-2.143,4.926C53.244,51.17,37.809,61.543,35.635,62.82c-1.732,1-3.326,2.395-5.8,2.395A9.825,9.825,0,0,1,25.52,64.045ZM22.51,39.5l-.229-.865a.706.706,0,0,1,.129-.607.688.688,0,0,1,.557-.275H35.734a.689.689,0,0,1,.547.275.7.7,0,0,1,.121.607l-.219.865a7.065,7.065,0,0,1-13.674,0Zm6.84,2.486a4.265,4.265,0,0,0,3.178-1.424H26.174A4.239,4.239,0,0,0,29.35,41.982Zm-6.285-5.07a.885.885,0,1,1,0-1.77H35.658a.885.885,0,0,1-.008,1.77Zm-.189-2.637a.7.7,0,0,1-.707-.7V31.021a.565.565,0,0,0-.244-.461,13.168,13.168,0,1,1,14.844,0,.563.563,0,0,0-.242.461v2.547a.7.7,0,0,1-.7.707Zm8.672-8.785a6.207,6.207,0,0,0,2.455-.3c.547-.258.721-.676.721-1.572V14.719H33.059v8.887c0,.219-.1.281-.334.3-.234,0-1.033,0-1.732-.039A6.217,6.217,0,0,1,31.547,25.49Zm-6.18-2.166c0,1.535.463,1.967,1.969,1.967h1.7c1.285,0,1.717-.516,1.877-2.174a4.544,4.544,0,0,1-1.443-.607c-.062,1.141-.145,1.361-.586,1.361H27.557c-.494,0-.578-.055-.578-.562V20.117h1.475a3.131,3.131,0,0,1-.213,1.223.374.374,0,0,1-.334.131,6.154,6.154,0,0,1-.836-.047,3.419,3.419,0,0,1,.41,1.4,8.144,8.144,0,0,0,1.3-.045,1.284,1.284,0,0,0,.844-.455c.281-.35.395-1.223.465-3.107l.016-.2.744-.707v4.154h1.619V15.793H30.848V18.17a28.18,28.18,0,0,0-2.326-2.758c.084-.158.152-.328.221-.486l-1.535-.479a9.09,9.09,0,0,1-3.215,3.9,7.919,7.919,0,0,1,1.2,1.27l.174-.129Zm.906-4.643a11.211,11.211,0,0,0,1.465-1.855c.518.609,1.049,1.27,1.469,1.855Zm17.676-2.123a1.606,1.606,0,0,1,1.186-1.943l2.363-.578a1.608,1.608,0,0,1,.76,3.125l-2.369.576a1.629,1.629,0,0,1-.383.047A1.611,1.611,0,0,1,43.949,16.559ZM12.631,17.631,10.389,16.7a1.608,1.608,0,0,1,1.23-2.971l2.242.941a1.6,1.6,0,1,1-1.23,2.963Zm4.088-9.514L15.328,6.125a1.605,1.605,0,0,1,2.637-1.832l1.391,1.99a1.6,1.6,0,0,1-.4,2.234,1.58,1.58,0,0,1-.916.289A1.6,1.6,0,0,1,16.719,8.117Zm22.709.32a1.614,1.614,0,0,1-.273-2.252l1.488-1.914A1.6,1.6,0,1,1,43.174,6.24L41.686,8.16a1.626,1.626,0,0,1-2.258.277ZM27.746,4.043V1.6a1.607,1.607,0,0,1,3.215,0V4.043a1.607,1.607,0,0,1-3.215,0Z" transform="translate(0 0)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#2bbaff"/><stop offset="0.498" stop-color="#1a8cfd"/><stop offset="1" stop-color="#006aef"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M43.013,57.336h-.255l-.074,0a14.064,14.064,0,0,1-8.911-3.467,6.216,6.216,0,0,1,6.1-5.029h6.278a6.218,6.218,0,0,1,6.1,5.03A14.073,14.073,0,0,1,43.6,57.324h-.009l-.067,0H43.5l-.063,0h-.424ZM30.159,54.9H8.5a1.717,1.717,0,0,1-1.715-1.716v-10.1A1.717,1.717,0,0,1,8.5,41.363H20.6a1.717,1.717,0,0,0,1.716-1.715V37.73H11.824a1.717,1.717,0,0,1-1.716-1.715V8.8a1.718,1.718,0,0,1,1.716-1.716h8.768V3.437A3.44,3.44,0,0,1,24.029,0h6.93A3.441,3.441,0,0,1,34.4,3.437V7.089H42.87A1.718,1.718,0,0,1,44.586,8.8V26.022c-.515-.046-1.044-.07-1.574-.07A17.327,17.327,0,0,0,30.157,54.9Zm4.219-36.07a3.437,3.437,0,1,0,3.438,3.437A3.441,3.441,0,0,0,34.378,18.828Zm-13.619,0A3.437,3.437,0,1,0,24.2,22.265,3.441,3.441,0,0,0,20.758,18.828ZM24.029,3.437V7.083h6.924V3.437Zm7.256,47.59v0a14.059,14.059,0,1,1,23.456,0,9.508,9.508,0,0,0-8.589-5.455H44.686a7.193,7.193,0,1,0-3.347,0H39.873a9.5,9.5,0,0,0-8.587,5.457ZM43.013,42.5a3.923,3.923,0,1,1,3.923-3.924A3.928,3.928,0,0,1,43.013,42.5ZM6.844,31.07a1.717,1.717,0,0,1-1.716-1.715V15.176a1.715,1.715,0,1,1,3.431,0V29.355A1.717,1.717,0,0,1,6.844,31.07ZM49.8,27.327h0a17.187,17.187,0,0,0-3.429-1.051v-11.1a1.715,1.715,0,1,1,3.431,0v12.15Zm3.406-.007a1.717,1.717,0,0,1-1.715-1.715V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,53.206,27.32Zm-51.491,0A1.717,1.717,0,0,1,0,25.605V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,1.715,27.32Z" transform="translate(-14477.664 23050.15)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.414" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#2bbaff"/><stop offset="0.498" stop-color="#1a8cfd"/><stop offset="1" stop-color="#006aef"/></linearGradient></defs><g transform="translate(-2.29 3.525)"><g class="a" transform="translate(2.29 -3.525)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M36.066,58.469a15.431,15.431,0,0,1,0-21.866,15.011,15.011,0,0,1,3.577-2.662,2.018,2.018,0,0,1,1.878,3.571,11.53,11.53,0,0,0-2.6,1.947A11.446,11.446,0,0,0,55.132,55.622a11.938,11.938,0,0,0,1.878-2.462A2.02,2.02,0,1,1,60.5,55.2,15.711,15.711,0,0,1,58,58.469a15.533,15.533,0,0,1-21.929,0Zm-5.87-.994H5.225A5.225,5.225,0,0,1,0,52.263V13.925A5.226,5.226,0,0,1,5.225,8.712H53.769A5.226,5.226,0,0,1,59,13.925V32.117A19.526,19.526,0,0,0,30.2,57.474v0ZM21.753,18.77l-8.5,7.4a2.531,2.531,0,0,0-.239,3.565,2.536,2.536,0,0,0,3.568.239l6.835-5.958L28.446,28.4a2.52,2.52,0,0,0,3.351-.015L42.282,19a2.508,2.508,0,0,0,.191-3.557,2.529,2.529,0,0,0-3.567-.192L30.085,23.14l-5-4.369a2.544,2.544,0,0,0-3.335,0ZM47.03,49.554a2.017,2.017,0,0,1-2.022-2.017V34.091a2.021,2.021,0,0,1,2.022-2.017A15.485,15.485,0,0,1,62.537,47.537a2.018,2.018,0,0,1-2.024,2.017Zm2.025-4.034h9.258a11.471,11.471,0,0,0-9.258-9.229ZM7.53,5.051a2.521,2.521,0,1,1,0-5.043H50.681a2.521,2.521,0,1,1,0,5.043Z" transform="translate(6.296 0.013)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="582" height="667" viewBox="0 0 582 667"><image width="582" height="667" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 664 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="53" height="53" viewBox="0 0 53 53"><defs><style>.a{fill:rgba(0,121,254,0.3);stroke:rgba(0,121,254,0.5);}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#92eeff"/><stop offset="1" stop-color="#00c7ff"/></linearGradient></defs><g transform="translate(0.5 -115.502)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(2.236 118.236)"><path class="b" d="M9204.336-22218.762a6.4,6.4,0,0,1-2.489-.691,6.242,6.242,0,0,1-2-1.615,6.363,6.363,0,0,1-1.206-2.283,6.357,6.357,0,0,1-.246-1.863c-.047-.033-.094-.066-.139-.1a6.4,6.4,0,0,1-2.272-3.4,6.418,6.418,0,0,1,.268-4.076,6.336,6.336,0,0,1,1.233-1.912,6.383,6.383,0,0,1-.4-1.973,6.41,6.41,0,0,1,.53-2.809,6.441,6.441,0,0,1,1.7-2.289,6.424,6.424,0,0,1,1.751-1.057,4.969,4.969,0,0,1,.343-1.289,4.965,4.965,0,0,1,1.334-1.859,5.038,5.038,0,0,1,2.016-1.082,5.037,5.037,0,0,1,2.289-.074,5.024,5.024,0,0,1,2.089.943,4.947,4.947,0,0,1,.871.861,5.147,5.147,0,0,1,.876-.861,5,5,0,0,1,2.083-.943,5.035,5.035,0,0,1,2.289.074,5.06,5.06,0,0,1,2.021,1.082,5.031,5.031,0,0,1,1.334,1.859,5.008,5.008,0,0,1,.343,1.289,6.424,6.424,0,0,1,1.751,1.057,6.441,6.441,0,0,1,1.7,2.289,6.405,6.405,0,0,1,.524,2.809,6.434,6.434,0,0,1-.4,1.973,6.315,6.315,0,0,1,1.234,1.912,6.418,6.418,0,0,1,.268,4.076,6.4,6.4,0,0,1-2.272,3.4l-.143.105a6.214,6.214,0,0,1-.248,1.859,6.26,6.26,0,0,1-1.2,2.283,6.271,6.271,0,0,1-2.01,1.615,6.354,6.354,0,0,1-2.485.691c-.14.006-.278.012-.418.012a6.213,6.213,0,0,1-2.139-.375,6.394,6.394,0,0,1-2.2-1.34,6.4,6.4,0,0,1-.915-1.066,6.415,6.415,0,0,1-.91,1.066,6.427,6.427,0,0,1-2.206,1.34,6.283,6.283,0,0,1-2.143.377C9204.609-22218.748,9204.473-22218.752,9204.336-22218.762Zm6.768-6.342a4.232,4.232,0,0,0,.346,1.652,4.123,4.123,0,0,0,.972,1.379,4.116,4.116,0,0,0,1.44.877,4.062,4.062,0,0,0,1.67.234,4.159,4.159,0,0,0,1.63-.447,4.159,4.159,0,0,0,1.313-1.061,4.227,4.227,0,0,0,.787-1.49c.02-.07.037-.139.054-.209a6.32,6.32,0,0,1-1.422.164,1.1,1.1,0,0,1-1.1-1.1,1.1,1.1,0,0,1,1.1-1.1,4.178,4.178,0,0,0,2.529-.859,4.138,4.138,0,0,0,1.485-2.221,4.216,4.216,0,0,0-.173-2.67,4.2,4.2,0,0,0-1.765-2.01,1.1,1.1,0,0,1-.4-1.5,1.1,1.1,0,0,1,1.063-.543,4.16,4.16,0,0,0,.1-.758,4.249,4.249,0,0,0-.346-1.838,4.156,4.156,0,0,0-1.117-1.5,4.078,4.078,0,0,0-.569-.408,4.928,4.928,0,0,1-.385.838,1.1,1.1,0,0,1-.955.553,1.08,1.08,0,0,1-.547-.15,1.093,1.093,0,0,1-.4-1.5,2.906,2.906,0,0,0,.374-1.229,1.022,1.022,0,0,1,.006-.145,2.841,2.841,0,0,0-.218-1.133,2.836,2.836,0,0,0-.754-1.051,2.794,2.794,0,0,0-1.139-.607,2.8,2.8,0,0,0-1.29-.045,2.782,2.782,0,0,0-1.173.535,2.84,2.84,0,0,0-.82.994,2.912,2.912,0,0,0-.3,1.262v5.254a4.426,4.426,0,0,0,.877,2.625,4.4,4.4,0,0,0,2.277,1.58,1.1,1.1,0,0,1,.748,1.361,1.1,1.1,0,0,1-1.367.748,6.6,6.6,0,0,1-2.535-1.41v6.928Zm-10.352,1.145a4.119,4.119,0,0,0,.787,1.49,4.148,4.148,0,0,0,1.313,1.061,4.105,4.105,0,0,0,1.624.447,4.076,4.076,0,0,0,1.676-.234,4.125,4.125,0,0,0,1.44-.877,4.208,4.208,0,0,0,.972-1.379,4.226,4.226,0,0,0,.34-1.652v-6.924a6.628,6.628,0,0,1-2.534,1.406,1.117,1.117,0,0,1-.308.045,1.1,1.1,0,0,1-1.055-.793,1.093,1.093,0,0,1,.748-1.361,4.393,4.393,0,0,0,2.272-1.58,4.354,4.354,0,0,0,.876-2.625v-5.254a2.906,2.906,0,0,0-.29-1.262,2.84,2.84,0,0,0-.82-.994,2.778,2.778,0,0,0-1.179-.535,2.8,2.8,0,0,0-1.29.045,2.832,2.832,0,0,0-1.139.607,2.821,2.821,0,0,0-.748,1.051,2.819,2.819,0,0,0-.212,1.271,2.821,2.821,0,0,0,.374,1.234,1.1,1.1,0,0,1-.4,1.5,1.1,1.1,0,0,1-1.5-.4,5.009,5.009,0,0,1-.386-.838,4.127,4.127,0,0,0-.568.408,4.156,4.156,0,0,0-1.117,1.5,4.249,4.249,0,0,0-.346,1.838,4.246,4.246,0,0,0,.1.758,1.106,1.106,0,0,1,1.064.543,1.1,1.1,0,0,1-.4,1.5,4.2,4.2,0,0,0-1.765,2.01,4.216,4.216,0,0,0-.173,2.67,4.138,4.138,0,0,0,1.485,2.221,4.178,4.178,0,0,0,2.529.859,1.1,1.1,0,0,1,1.1,1.1,1.1,1.1,0,0,1-1.1,1.1,6.32,6.32,0,0,1-1.422-.164C9200.714-22224.1,9200.732-22224.029,9200.752-22223.959Z" transform="translate(-9186.242 22256.754)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="53" height="53" viewBox="0 0 53 53"><defs><style>.a{fill:rgba(0,121,254,0.3);stroke:rgba(0,121,254,0.5);}.b{opacity:0;}.b,.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#92eeff"/><stop offset="1" stop-color="#00c7ff"/></linearGradient></defs><g transform="translate(0.5 -115.502)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18559 4825)"><rect class="b" width="42" height="42" transform="translate(-18554 -4704)"/><path class="c" d="M-9736.837-26950.139a1.008,1.008,0,0,1-.542-.889v-3.371h-.752a4.506,4.506,0,0,1-4.5-4.5v-2.629c-1.89-.08-3.366-2-3.366-4.367s1.477-4.287,3.366-4.369v-2.633a4.5,4.5,0,0,1,4.5-4.5h15.658v.129a3.676,3.676,0,0,0,.494,1.869h-16.152a2.5,2.5,0,0,0-2.5,2.5v14a2.5,2.5,0,0,0,2.5,2.5h1.741a1.006,1.006,0,0,1,1.009,1v2.432l4.544-3.244a.97.97,0,0,1,.576-.189h13.124a2.5,2.5,0,0,0,2.506-2.5v-9.441a3.524,3.524,0,0,0,1.118.189h.033a3.634,3.634,0,0,0,2.764-1.293,4.793,4.793,0,0,1,1.456,3.549,5.014,5.014,0,0,1-.982,3.041,3.23,3.23,0,0,1-2.391,1.334v2.621a4.507,4.507,0,0,1-4.5,4.5h-12.806l-5.858,4.184a1.021,1.021,0,0,1-.582.191A1.007,1.007,0,0,1-9736.837-26950.139Zm1.334-10.389a1.876,1.876,0,0,1-1.876-1.877v-7.869a1.876,1.876,0,0,1,1.876-1.877h15.739a1.876,1.876,0,0,1,1.876,1.877v7.869a1.876,1.876,0,0,1-1.876,1.877Zm10.931-5.811a1.752,1.752,0,0,0,1.754,1.746,1.751,1.751,0,0,0,1.747-1.746,1.754,1.754,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9724.572-26966.338Zm-9.617,0a1.752,1.752,0,0,0,1.748,1.746,1.751,1.751,0,0,0,1.747-1.746,1.755,1.755,0,0,0-1.747-1.756A1.755,1.755,0,0,0-9734.189-26966.338Zm20.1-5.277-.453-1.551a4.433,4.433,0,0,0-2.946-3.006l-1.537-.467a.649.649,0,0,1-.447-.611.524.524,0,0,1,.021-.148.616.616,0,0,1,.217-.346.624.624,0,0,1,.217-.115l.284-.088,1.232-.365a4.417,4.417,0,0,0,2.96-3.02l.46-1.551a.625.625,0,0,1,.42-.434v.006a.538.538,0,0,1,.183-.033.574.574,0,0,1,.292.08.581.581,0,0,1,.3.381l.46,1.557a4.422,4.422,0,0,0,2.96,3.014l1.171.346.346.107a.647.647,0,0,1,.454.609.641.641,0,0,1-.447.611l-1.537.467a4.434,4.434,0,0,0-2.946,3.006l-.453,1.551a.631.631,0,0,1-.6.461A.636.636,0,0,1-9714.089-26971.615Zm-4.571-7.34-.183-.623a2.7,2.7,0,0,0-1.829-1.83l-.623-.189a.29.29,0,0,1-.2-.277.284.284,0,0,1,.2-.277l.61-.184a2.7,2.7,0,0,0,1.842-1.842l.183-.615a.32.32,0,0,1,.2-.2.327.327,0,0,1,.224.027.275.275,0,0,1,.143.17l.183.615a2.713,2.713,0,0,0,1.842,1.842l.609.184a.289.289,0,0,1,.21.277.3.3,0,0,1-.21.277l-.257.076-.366.113a2.725,2.725,0,0,0-1.828,1.83l-.183.623a.293.293,0,0,1-.278.2A.3.3,0,0,1-9718.66-26978.955Z" transform="translate(-8805.37 22282.029)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.7 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="53" height="53" viewBox="0 0 53 53"><defs><style>.a{fill:rgba(0,121,254,0.3);stroke:rgba(0,121,254,0.5);}.b{fill:#fff;opacity:0;}.c{fill:url(#a);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#92eeff"/><stop offset="1" stop-color="#00c7ff"/></linearGradient></defs><g transform="translate(0.5 -115.502)"><rect class="a" width="52" height="52" rx="8" transform="translate(0 116.002)"/><g transform="translate(18558 4829)"><rect class="b" width="42" height="42" transform="translate(-18553 -4708)"/><path class="c" d="M-9520.252-26774.373h-17.5a8.261,8.261,0,0,1-8.248-8.254v-8.746a8.261,8.261,0,0,1,8.248-8.256h7.75v-2.582a2.5,2.5,0,0,1-1.5-2.287,2.506,2.506,0,0,1,2.5-2.5,2.5,2.5,0,0,1,2.5,2.5,2.515,2.515,0,0,1-1.5,2.293v2.576h2.752a1.254,1.254,0,0,1,1.251,1.252,1.254,1.254,0,0,1-1.251,1.252h-12.5a5.758,5.758,0,0,0-5.752,5.752v8.746a5.758,5.758,0,0,0,5.752,5.752h17.5a5.758,5.758,0,0,0,5.752-5.752v-5.746a1.252,1.252,0,0,1,1.251-1.25,1.252,1.252,0,0,1,1.252,1.25v5.746A8.264,8.264,0,0,1-9520.252-26774.373Zm-2.624-6.25h-12.251a5.506,5.506,0,0,1-5.5-5.5,5.5,5.5,0,0,1,5.5-5.5h12.251a5.507,5.507,0,0,1,5.5,5.5A5.509,5.509,0,0,1-9522.876-26780.623Zm-.989-7.812a.992.992,0,0,0-.706.291l-1.312,1.313a1,1,0,0,0-.289.707.985.985,0,0,0,.289.705l1.313,1.313a1,1,0,0,0,.706.3,1,1,0,0,0,.706-.3.988.988,0,0,0,.293-.707.987.987,0,0,0-.293-.705l-.605-.605.605-.605a.988.988,0,0,0,.293-.707.988.988,0,0,0-.293-.707A.988.988,0,0,0-9523.865-26788.436Zm-10.388.561a1.751,1.751,0,0,0-1.749,1.75,1.75,1.75,0,0,0,1.749,1.748,1.75,1.75,0,0,0,1.749-1.748A1.751,1.751,0,0,0-9534.253-26787.875Zm19.262-3.531a.587.587,0,0,1-.552-.4l-1.5-4.568-4.555-1.447a.593.593,0,0,1-.4-.551.577.577,0,0,1,.4-.553l4.5-1.514,1.419-4.5a.59.59,0,0,1,.557-.412.609.609,0,0,1,.17.027.569.569,0,0,1,.377.377l1.5,4.568,4.7,1.668a.579.579,0,0,1,.384.559.59.59,0,0,1-.417.545l-4.6,1.293-1.426,4.5A.572.572,0,0,1-9514.991-26791.406Z" transform="translate(-9002.999 22102.623)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="1920" height="1080" viewBox="0 0 1920 1080"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 3840 2160"><image width="3840" height="2160" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 4.3 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="582" height="667" viewBox="0 0 582 667"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 1164 1312"><image width="1164" height="1312" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABIwAAAUgCAYAAAAi/8yOAAAgAElEQVR4nOy9h5rrWHaleQwAunDXZmZlVmVleacqebVK3dP9WPMm8zrzjesejdSfTEsqeZVaqsq894algTtmvn3OPuAhg4yI6zKvWX8mLkgQAEESZAALa68t/9f/zQsAXjXDXrVn9/L7pt+23As+fttyd17+rs//mtdzy+ThgTt/u59z/n2f30tvx/Ou/xUt96LP+7LP97Lrue3zf1Fe13qvre5Vr++Vz/hub9ctTyt5UNntfYPamn8khBgLIWZCiAnfr3icD+Md00bZ/DRoIUQhhCj5fsHPUfD9kufRfLvkxwqeJne83LStRba82vP2OCGEFUL0QgjDy/s967U8j+H5e56Wlm/5sbTOLltvut/xfLuGZse0NH8thFhm87hsW/Pb+4Z8nms7wlfCHZ/4S9++W57wdW2PfNUr3rO+l36aV7zeV/W6n3c9L/u8L7r8c2/ntRuvZv3Pvd5b5t+7GvmK5nvF67n1Ze+b77blX/LxvZ/fXbcbgBegwJsGAAAAAEZmwksuvmwPOhNztoeKhaJJJgqVW0JQtUMcqrbu7xODVCb2bG/L9rSbBKN9ItE+3B0EI5sJRmZrWrclGO0SlXLRqNshIm1PS0JUw6JRnT3P9mC3RK3toc8GXE0EAAAAAAQjAAAA4D1HsrhzwK4gGk+FEIc8TsOMBaAkBKXb6fFJJvTkIpLKXDz5eN/tfJyLO3rrvvqSL6jeJjDddEyVBKXc4WN3OIHsjnE+bdfjbofw07F4tOKhZlEpF5ZWW8Oc7y/YrbTg+SAeAQAAAO8pEIwAAACAdwediTa7xsWWg6jMSseSYJSG5xGMkqMI7EZ+BcdcuTCUC0arbJwPcxaKlluC0XLLfbQ9dOL62GI/AAAAAN5+IBgBAAAAbz8k1hwLIY54OOTxAU8/4GmzTBii+2MZhZ+8nKvMMoL2laPlZV/gzSSJePe3ytH2laV1W+V0aZyEpjmLSMmBlASmS56Wj694qLFvAAAAAG8vEIwAAACAN5PtTJ99t6eZMPS8gtFrL+m6JaPzuR8blr9hpq8q+POm2q27hLzfuPwLLJOhM/fZi+BfQDC65MdXe7KZmq18JvOC2wYAAACA1wQEIwAAAODNIok893l8wuLPvWx8nAlDs0xQ2leKlpekvRGuoH1Ch7yjCJIEmF3i0JsUuvPcXSJf03a8JDITI+0dStJygSiVuyUR6TwbX2T3z+BKAgAAAN4sIBgBAAAAXw6aRZ3JnlbyKQ/o+A6C0VHmHHplbIgv8roYc9P9/LbPxiTs+Owm36Wx88LTBMfzeh+np8eHRfPl1uv1PtONvN+cL07YQ0yZTsvfLNHI+MqkFPLGjtRSxndMRvOTXC/HD8t8eSnTfPky6+lSprdfSqFknEdtLhfHKvucdn0G27f33vf7H98iuZXGN8+2Qe48ukkwuuShzpxHbeZIarMxcpIAAACA1wwEIwAAAOD1oljgeSiEeMDje3z7hG/fEzIIRLOsFf1oqxQtb09fvo4t3u4XnwsHu5w/+fwbIpEQ3nlhvfDGCm+8cM4Jb0kksl7E+95bJ3wYh/nD497ZMHY0X+gq5oJ45J31tErP4hItFOanx8M0WogeT/M775MotOt1huXCvD6JVNeRLPQoEQa1Q0Pj90ZKFSQiqVQQdaTSMnZVi8tJqel/1o/i42FelcQhJQUtorQI89FjOk6XmuZTYXlF6y1IPIqPK6W9LKSQRVz+eqXenUvZ5M3zvyQHPDzOBKB2qyQt3U+B2xeZoHTBghLdPuXhGQtQ7vVsMgAAAAAgGAEAAAAvRxJ3xjuGSeYGulkwisMLx+/sc/vI7MYuJ4rY6vXug/ASxZco/PgkxAz3RRBqwjx0fy2+COFc0IREEoSM8944uiuEdTSE6SQgBY2H5wvrovk9P25d3A6fRKG4HfE5h2mDU0kM2+Gz8Q2CkeDlaRA36CQkFAXRhwWjPe+9TMKSSmMlBzeQWgtOMrmH6PFBMGLrkFJCaRaIaD6t4nxBGFJCaEXj8HgQh9L9QgXBKAhMYR28fqnWAhY9R3gael4ZX5eScTvpvlpvlwivU+7ZT0TmSLrJubTnDS3vKHb2dxSMLlg0am4Yujs8HwAAAAB2AMEIAAAAeDEmLPI85PKxfPyAh3syCkaTHWJSXo6mXtdnkE7cZXaC7zPxKCguQawRvRGOBJ7eksjjXU9uH5pmheuNd70hx5BzQdAh55ARzhpnTU/zeUtuIus8Pb5RdrZZZpYJQWKjDE34dYnaUJIm8nKzrISMHx9u8500n78xY3q9bp9m3CsYeUlWJ+nk7iq9bEYRS808l5nJrByNy87EZqnaRtnaUJLGJWjZPGk5yTVrakf5WhSDgiNJaXIplUoXpVC6kKrQIkwrSEzSSulCyKKQqtRClUV8rFQ0n5QliU+FUIUSogwuptx5dPeytZcNHidR6RF/n3aVpKWh5hK2iy0h6YzHdP8pC03ty20SAAAA8P4BwQgAAADYjcxyhcZZm/IJl47d3yEUbQtGJy8SMn2bW2hQIrLHXHLO+ODkYUdQdOak0q/BVeOp9Cu4fpz1zpC7xwrfkzBEjiASjOg2CUA2Ckd9HwUhFoyikESCkb0uGDm/uXHXdJYdm3/j23G3GWVmoAriyV2WeWUt1dbiluCiOb/10HWNxe+avl+J2SGCZTKOjy9FyVjWRoJRkQlGUQSSQTAi8aiUuiChSIfHJYlHJBiRU4nmL2kalbppGR1LOrqZVHJbcYkdO5SGErrBoaS2tzIPnNrzUne8dM3fv+nedyV2V7u8RTBK7qQVi0y7hjc0bxwAAAD46oBgBAAAAFxnynkrNHzAbofH2ZA6lY2zEOtxFl49fpluZLuygeTWifdwXwaxiDJ9uuAEcq4N7h/v6L7phW1774xxtu2FM523Xe9t33lLjiEShCyXnw1laJ7Lv1IeEJeYZRlBcZ4hLyiUkg3lYpsbHoQcn+syMp/jmngkr/2zzy0kNxfcSFy6qYnazQ/s4RY1Yaf2I+5gytl8/Fqd167XvmX22ZyFBDsrpDXOmY1SuFSK5mLGUl6KxuV2Ks0jxfCYIsGoEFJXUpel1GUldVUKXZRKjUh0KoQakdhUSFWRyFQoGqtSS1mR42nfO3MHseiuFJk4+3EWmL3tREqB2094+IJFpc/5/lMWlAAAAADAQDACAADwvjLNhuQkGnHm0MktgtHx875nO51CYm1yyQUidgpxJlBwBll2CoXbNogCcZoRlqb1a8GIx8Eh5MgZ1FE5We9s14f7LohFnTehxMwJl52rb5p5dvlvrk+LlVFakkD2iuw6byC3vLK9pim58+YNq3l1jqeQBs6fL+l4Qze6NEM+79bSw30llKQStkoWZRSNVFkKXZZKVSQgRaEolLbFsQpuJRaMZFkITblMwfWkpQpOpDBEt5JOzqSUCL79Pcg37paMJM3Ov9kNb8vlLYJRnomUXEjLzJkEAAAAvFdAMAIAAPC+MWFHwkdCiA95/JhvP+CyssOtErR8eCHn0C7XULrjMwcRlZNRCZjxlpxC5AZqyS3Ue9f2IriDus7ZthGmbakczFsShkKgtMjCoYeStLXYNJSjudh1zG44giJyywm0jjuSg6HHb84ft367wxr46sjcR9cMPsP9dXjTdpb1hmBEOpMT0lnR29abbihLczKVqKWubiqFeYtwX2gqhSNRaaR0MRbFqFKaXEnkUKpKSQ4lNSqkJmdSVYg4ViKWtN0kDr2EG+mYu7V9xCJQk4lBdHuelbZ9wULSr7PhlOcDAAAA3gsgGAEAAHgXUVsOomnmPnjAjqF9gtHB87wf+3KF5Ja6MohB6+5hNgg9cexMGFN+UCgVS4IRiUVRKHKuM8J2nbctlZU13rSdC6VlIZtoiFpeP/8NbqHQ5r2ExPNust4V5Q3Wp+f77ElYssKRymhF6HAn/D6XkucIchKRKql1pXQ5lsWocrqqpB6ROFQpFcZcyhaEo0LISktN+UlFEVxJilxJyZEUM5ik1JpFJZF9x7ZdSNt5SRk6a/O/i/kNglHKRVpmzqN8QIt/AAAA7xQQjAAAALxrHLAA9BGXk32Nb38tCEIy5A9tC0nJQfTCCsouF0Q6mbVC2Cj+BLGn6Z1tOmGbIP4427betEEA8tYYb3t2GZFjyA5h1evQamtZZIrh1d5l8TeDbrXDHRRvxligkCoEuQjchbyGza+dSDtdSrlDyQrhOm+dcc62wnYk9nAZGjmRhtI0QUIQu5KKmJNUkMA0okEV5EoaVUJNShXG40IWIxKZtBB6rxvpxXfuQ/4NecTOo1wQWnLZGglHv+Jytl+xuPRrFpgW2KkAAAC8K0AwAgAA8LYy4RO75Bw64JO9h3yy97UdgtG9u5SUPU/eUKj7CoKQY9dQDJIm9xC5hoxwnQ0t6V0oLSPByHjbtH4QjJpWmK5xJoRTW2G57bzMM112OIcooTi4LrADg9fKVk1ipj7ebd+j/dkI640XxgvRp4lJWeKixiBwaqFVKVUxVkU1EkEwGpNgNJJqUjg9qqQekysphG3HcVkE11F0I+koQtH9QglRaLn5fb1jLpK8IQ/Jcte1bcHoV5yD9JRdSsmFtOAxMpALine truncated

Before

Width:  |  Height:  |  Size: 968 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" width="1" height="1" patternTransform="matrix(-1, 0, 0, 1, 278, 0)" viewBox="0 0 139 765"><image preserveAspectRatio="xMidYMid slice" width="139" height="765" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 53 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 278 1530"><image width="278" height="1530" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 53 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#a6cfff"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M110.023,105.37H98.2a1.721,1.721,0,0,1-1.716-1.716v-1.918h10.189a1.721,1.721,0,0,0,1.716-1.716V72.8a1.721,1.721,0,0,0-1.716-1.716H98.2V67.437A3.444,3.444,0,0,0,94.76,64H87.83a3.444,3.444,0,0,0-3.437,3.437v3.652H75.625A1.721,1.721,0,0,0,73.91,72.8v27.21a1.721,1.721,0,0,0,1.716,1.716h10.49v1.918a1.721,1.721,0,0,1-1.716,1.716H72.3a1.721,1.721,0,0,0-1.716,1.716v10.1A1.721,1.721,0,0,0,72.3,118.9h37.724a1.721,1.721,0,0,0,1.716-1.716v-10.1A1.726,1.726,0,0,0,110.023,105.37Zm-8.406-19.1a3.437,3.437,0,1,1-3.437-3.437A3.436,3.436,0,0,1,101.616,86.266ZM87.83,67.437h6.924v3.646H87.83ZM81.121,86.266A3.437,3.437,0,1,1,84.558,89.7,3.436,3.436,0,0,1,81.121,86.266Zm32.48-7.089V93.355a1.716,1.716,0,0,1-3.431,0V79.177a1.716,1.716,0,0,1,3.431,0Zm5.122,3.548v6.881a1.716,1.716,0,0,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0ZM70.644,95.07a1.717,1.717,0,0,1-1.716-1.716V79.177a1.716,1.716,0,0,1,3.431,0V93.355A1.713,1.713,0,0,1,70.644,95.07ZM67.231,82.724v6.881a1.716,1.716,0,1,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0Zm0,0" transform="translate(-14540.154 22987.455)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

@@ -1,47 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="188" height="241" viewBox="0 0 188 241" fill="none">
<defs>
<radialGradient id="surface" cx="0" cy="0" r="1" gradientTransform="translate(60 30) rotate(60) scale(150 158)" gradientUnits="userSpaceOnUse">
<stop stop-color="#46B6FF"/>
<stop offset=".24" stop-color="#1A83DE"/>
<stop offset=".6" stop-color="#075FBC"/>
<stop offset="1" stop-color="#003675"/>
</radialGradient>
<radialGradient id="inner-light" cx="0" cy="0" r="1" gradientTransform="translate(94 82) rotate(90) scale(79 84)" gradientUnits="userSpaceOnUse">
<stop stop-color="#0876DC" stop-opacity=".42"/>
<stop offset="1" stop-color="#001F55" stop-opacity="0"/>
</radialGradient>
<linearGradient id="lower-depth" x1="94" y1="118" x2="94" y2="165" gradientUnits="userSpaceOnUse">
<stop stop-color="#005DBB" stop-opacity="0"/>
<stop offset="1" stop-color="#002A68" stop-opacity=".58"/>
</linearGradient>
<linearGradient id="edge" x1="36" y1="12" x2="152" y2="160" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFFFFF" stop-opacity=".98"/>
<stop offset=".48" stop-color="#B6EAFF" stop-opacity=".78"/>
<stop offset="1" stop-color="#48BBFF" stop-opacity=".72"/>
</linearGradient>
<filter id="glow" x="-12" y="-12" width="212" height="212" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="4.5"/>
</filter>
<filter id="shadow" x="22" y="163" width="144" height="48" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feGaussianBlur stdDeviation="6.5"/>
</filter>
<clipPath id="clip">
<circle cx="94" cy="82" r="81"/>
</clipPath>
</defs>
<ellipse cx="94" cy="188" rx="61" ry="9" fill="#00112F" fill-opacity=".58" filter="url(#shadow)"/>
<circle cx="94" cy="82" r="82" fill="#139DFF" fill-opacity=".22" filter="url(#glow)"/>
<circle cx="94" cy="82" r="81" fill="url(#surface)"/>
<g clip-path="url(#clip)">
<circle cx="94" cy="82" r="79" fill="url(#inner-light)"/>
<ellipse cx="94" cy="142" rx="89" ry="38" fill="url(#lower-depth)"/>
<ellipse cx="94" cy="150" rx="78" ry="15" fill="#55B9FF" fill-opacity=".13"/>
<path d="M19 145C46 157 142 157 169 145" stroke="#BCEAFF" stroke-opacity=".24" stroke-width="1.2"/>
<path d="M30 160C54 169 134 169 158 160" stroke="#1599F7" stroke-opacity=".28" stroke-width="1.2"/>
<path d="M24 62C29 36 49 17 76 11" stroke="#D8F4FF" stroke-opacity=".3" stroke-width="9" stroke-linecap="round" filter="url(#glow)"/>
</g>
<circle cx="94" cy="82" r="81" stroke="url(#edge)" stroke-width="2"/>
<circle cx="94" cy="82" r="76" stroke="#27B2FF" stroke-opacity=".28"/>
<path d="M19 69C24 38 49 12 82 4" stroke="#FFFFFF" stroke-opacity=".88" stroke-width="2" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.431" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#a6cfff"/></linearGradient></defs><g transform="translate(-71.077 -67.746)"><g class="a" transform="translate(71.077 67.746)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M114.406,106.791a7.707,7.707,0,0,0-4.354,1.353L98.7,99.937a13.3,13.3,0,0,0,1.742-6.583c0-.421-.03-.842-.06-1.263L112,85.207a4.687,4.687,0,1,0-1.952-2.345L99.691,88.995a13.678,13.678,0,0,0-6.1-7.365l2.072-10.341c.15,0,.3.03.451.03a4.66,4.66,0,1,0-4.655-4.659,4.727,4.727,0,0,0,1.412,3.367l-2.1,10.462A13.479,13.479,0,0,0,80.05,81.87l-6.4-5.712A6.129,6.129,0,1,0,71.7,78.443L77.677,83.7a13.456,13.456,0,0,0,.691,19.991l-5.316,5.622a5.948,5.948,0,0,0-3.394-1.022,6.163,6.163,0,1,0,6.156,6.162,6.343,6.343,0,0,0-.721-2.916l5.826-6.193a13.464,13.464,0,0,0,16.1-2.946l11.022,7.966a7.77,7.77,0,0,0-1.2,4.118,7.658,7.658,0,1,0,15.316,0A7.817,7.817,0,0,0,114.406,106.791Zm0,0" transform="translate(13 9.671)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.337" x2="1" y2="1.007" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#a6cfff"/></linearGradient></defs><g transform="translate(-204.426 -230.797)"><rect class="a" width="68" height="68" transform="translate(204.426 230.797)"/><g transform="translate(209.658 232.191)"><path class="b" d="M25.52,64.045c-1.725-.852-8.6-4.486-10.846-5.656-2.309-1.207-3.3-1.01-5.09.146L6.346,60.67,0,46.383s6.887-3.254,10.033-4.508C15,39.885,17.273,41.6,20.115,43.4c1.209.762,5.131,3.664,5.131,3.664a17.886,17.886,0,0,0,7.783,2.316c5.928,0,6.975.344,6.975,2.266,0,2.113-3.859,2.266-3.883,2.266H26.605c-3.236,0-7.766-1.893-7.766-1.893s3.846,4.156,7.766,4.156h9.547c2.105-.047,6.1-1.047,6.1-4.537,0-4.529-4.066-4.529-9.219-4.529a5.2,5.2,0,0,1-1.127-.145c.2-.1.4-.207.639-.35.9-.523,2.145-1.27,3.535-2.158,3.67-2.3,5.555-2.592,7.387-.152a5.718,5.718,0,0,1,4.248-1.678c1.551,0,2.865,1.039,2.494,2.719,3.975-2.377,5.936-1.42,6.809-.266,1.156,1.527.373,3.109-2.143,4.926C53.244,51.17,37.809,61.543,35.635,62.82c-1.732,1-3.326,2.395-5.8,2.395A9.825,9.825,0,0,1,25.52,64.045ZM22.51,39.5l-.229-.865a.706.706,0,0,1,.129-.607.688.688,0,0,1,.557-.275H35.734a.689.689,0,0,1,.547.275.7.7,0,0,1,.121.607l-.219.865a7.065,7.065,0,0,1-13.674,0Zm6.84,2.486a4.265,4.265,0,0,0,3.178-1.424H26.174A4.239,4.239,0,0,0,29.35,41.982Zm-6.285-5.07a.885.885,0,1,1,0-1.77H35.658a.885.885,0,0,1-.008,1.77Zm-.189-2.637a.7.7,0,0,1-.707-.7V31.021a.565.565,0,0,0-.244-.461,13.168,13.168,0,1,1,14.844,0,.563.563,0,0,0-.242.461v2.547a.7.7,0,0,1-.7.707Zm8.672-8.785a6.207,6.207,0,0,0,2.455-.3c.547-.258.721-.676.721-1.572V14.719H33.059v8.887c0,.219-.1.281-.334.3-.234,0-1.033,0-1.732-.039A6.217,6.217,0,0,1,31.547,25.49Zm-6.18-2.166c0,1.535.463,1.967,1.969,1.967h1.7c1.285,0,1.717-.516,1.877-2.174a4.544,4.544,0,0,1-1.443-.607c-.062,1.141-.145,1.361-.586,1.361H27.557c-.494,0-.578-.055-.578-.562V20.117h1.475a3.131,3.131,0,0,1-.213,1.223.374.374,0,0,1-.334.131,6.154,6.154,0,0,1-.836-.047,3.419,3.419,0,0,1,.41,1.4,8.144,8.144,0,0,0,1.3-.045,1.284,1.284,0,0,0,.844-.455c.281-.35.395-1.223.465-3.107l.016-.2.744-.707v4.154h1.619V15.793H30.848V18.17a28.18,28.18,0,0,0-2.326-2.758c.084-.158.152-.328.221-.486l-1.535-.479a9.09,9.09,0,0,1-3.215,3.9,7.919,7.919,0,0,1,1.2,1.27l.174-.129Zm.906-4.643a11.211,11.211,0,0,0,1.465-1.855c.518.609,1.049,1.27,1.469,1.855Zm17.676-2.123a1.606,1.606,0,0,1,1.186-1.943l2.363-.578a1.608,1.608,0,0,1,.76,3.125l-2.369.576a1.629,1.629,0,0,1-.383.047A1.611,1.611,0,0,1,43.949,16.559ZM12.631,17.631,10.389,16.7a1.608,1.608,0,0,1,1.23-2.971l2.242.941a1.6,1.6,0,1,1-1.23,2.963Zm4.088-9.514L15.328,6.125a1.605,1.605,0,0,1,2.637-1.832l1.391,1.99a1.6,1.6,0,0,1-.4,2.234,1.58,1.58,0,0,1-.916.289A1.6,1.6,0,0,1,16.719,8.117Zm22.709.32a1.614,1.614,0,0,1-.273-2.252l1.488-1.914A1.6,1.6,0,1,1,43.174,6.24L41.686,8.16a1.626,1.626,0,0,1-2.258.277ZM27.746,4.043V1.6a1.607,1.607,0,0,1,3.215,0V4.043a1.607,1.607,0,0,1-3.215,0Z" transform="translate(0 0)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.1 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#a6cfff"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M43.013,57.336h-.255l-.074,0a14.064,14.064,0,0,1-8.911-3.467,6.216,6.216,0,0,1,6.1-5.029h6.278a6.218,6.218,0,0,1,6.1,5.03A14.073,14.073,0,0,1,43.6,57.324h-.009l-.067,0H43.5l-.063,0h-.424ZM30.159,54.9H8.5a1.717,1.717,0,0,1-1.715-1.716v-10.1A1.717,1.717,0,0,1,8.5,41.363H20.6a1.717,1.717,0,0,0,1.716-1.715V37.73H11.824a1.717,1.717,0,0,1-1.716-1.715V8.8a1.718,1.718,0,0,1,1.716-1.716h8.768V3.437A3.44,3.44,0,0,1,24.029,0h6.93A3.441,3.441,0,0,1,34.4,3.437V7.089H42.87A1.718,1.718,0,0,1,44.586,8.8V26.022c-.515-.046-1.044-.07-1.574-.07A17.327,17.327,0,0,0,30.157,54.9Zm4.219-36.07a3.437,3.437,0,1,0,3.438,3.437A3.441,3.441,0,0,0,34.378,18.828Zm-13.619,0A3.437,3.437,0,1,0,24.2,22.265,3.441,3.441,0,0,0,20.758,18.828ZM24.029,3.437V7.083h6.924V3.437Zm7.256,47.59v0a14.059,14.059,0,1,1,23.456,0,9.508,9.508,0,0,0-8.589-5.455H44.686a7.193,7.193,0,1,0-3.347,0H39.873a9.5,9.5,0,0,0-8.587,5.457ZM43.013,42.5a3.923,3.923,0,1,1,3.923-3.924A3.928,3.928,0,0,1,43.013,42.5ZM6.844,31.07a1.717,1.717,0,0,1-1.716-1.715V15.176a1.715,1.715,0,1,1,3.431,0V29.355A1.717,1.717,0,0,1,6.844,31.07ZM49.8,27.327h0a17.187,17.187,0,0,0-3.429-1.051v-11.1a1.715,1.715,0,1,1,3.431,0v12.15Zm3.406-.007a1.717,1.717,0,0,1-1.715-1.715V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,53.206,27.32Zm-51.491,0A1.717,1.717,0,0,1,0,25.605V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,1.715,27.32Z" transform="translate(-14477.664 23050.15)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.207" x2="0.793" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#a6cfff"/></linearGradient></defs><g transform="translate(-2.29 3.525)"><g class="a" transform="translate(2.29 -3.525)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M36.066,58.469a15.431,15.431,0,0,1,0-21.866,15.011,15.011,0,0,1,3.577-2.662,2.018,2.018,0,0,1,1.878,3.571,11.53,11.53,0,0,0-2.6,1.947A11.446,11.446,0,0,0,55.132,55.622a11.938,11.938,0,0,0,1.878-2.462A2.02,2.02,0,1,1,60.5,55.2,15.711,15.711,0,0,1,58,58.469a15.533,15.533,0,0,1-21.929,0Zm-5.87-.994H5.225A5.225,5.225,0,0,1,0,52.263V13.925A5.226,5.226,0,0,1,5.225,8.712H53.769A5.226,5.226,0,0,1,59,13.925V32.117A19.526,19.526,0,0,0,30.2,57.474v0ZM21.753,18.77l-8.5,7.4a2.531,2.531,0,0,0-.239,3.565,2.536,2.536,0,0,0,3.568.239l6.835-5.958L28.446,28.4a2.52,2.52,0,0,0,3.351-.015L42.282,19a2.508,2.508,0,0,0,.191-3.557,2.529,2.529,0,0,0-3.567-.192L30.085,23.14l-5-4.369a2.544,2.544,0,0,0-3.335,0ZM47.03,49.554a2.017,2.017,0,0,1-2.022-2.017V34.091a2.021,2.021,0,0,1,2.022-2.017A15.485,15.485,0,0,1,62.537,47.537a2.018,2.018,0,0,1-2.024,2.017Zm2.025-4.034h9.258a11.471,11.471,0,0,0-9.258-9.229ZM7.53,5.051a2.521,2.521,0,1,1,0-5.043H50.681a2.521,2.521,0,1,1,0,5.043Z" transform="translate(6.296 0.013)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" width="1" height="1" patternTransform="matrix(-1, 0, 0, 1, 278, 0)" viewBox="0 0 139 765"><image preserveAspectRatio="xMidYMid slice" width="139" height="765" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 51 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="139" height="765" viewBox="0 0 139 765"><defs><style>.a{fill:url(#a);}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 278 1530"><image width="278" height="1530" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 51 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="54.923" height="54.898" viewBox="0 0 54.923 54.898"><defs><style>.a{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><path class="a" d="M110.023,105.37H98.2a1.721,1.721,0,0,1-1.716-1.716v-1.918h10.189a1.721,1.721,0,0,0,1.716-1.716V72.8a1.721,1.721,0,0,0-1.716-1.716H98.2V67.437A3.444,3.444,0,0,0,94.76,64H87.83a3.444,3.444,0,0,0-3.437,3.437v3.652H75.625A1.721,1.721,0,0,0,73.91,72.8v27.21a1.721,1.721,0,0,0,1.716,1.716h10.49v1.918a1.721,1.721,0,0,1-1.716,1.716H72.3a1.721,1.721,0,0,0-1.716,1.716v10.1A1.721,1.721,0,0,0,72.3,118.9h37.724a1.721,1.721,0,0,0,1.716-1.716v-10.1A1.726,1.726,0,0,0,110.023,105.37Zm-8.406-19.1a3.437,3.437,0,1,1-3.437-3.437A3.436,3.436,0,0,1,101.616,86.266ZM87.83,67.437h6.924v3.646H87.83ZM81.121,86.266A3.437,3.437,0,1,1,84.558,89.7,3.436,3.436,0,0,1,81.121,86.266Zm32.48-7.089V93.355a1.716,1.716,0,0,1-3.431,0V79.177a1.716,1.716,0,0,1,3.431,0Zm5.122,3.548v6.881a1.716,1.716,0,0,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0ZM70.644,95.07a1.717,1.717,0,0,1-1.716-1.716V79.177a1.716,1.716,0,0,1,3.431,0V93.355A1.713,1.713,0,0,1,70.644,95.07ZM67.231,82.724v6.881a1.716,1.716,0,1,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0Zm0,0" transform="translate(-63.8 -64)"/></svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.431" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(-71.077 -67.746)"><g class="a" transform="translate(71.077 67.746)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M114.406,106.791a7.707,7.707,0,0,0-4.354,1.353L98.7,99.937a13.3,13.3,0,0,0,1.742-6.583c0-.421-.03-.842-.06-1.263L112,85.207a4.687,4.687,0,1,0-1.952-2.345L99.691,88.995a13.678,13.678,0,0,0-6.1-7.365l2.072-10.341c.15,0,.3.03.451.03a4.66,4.66,0,1,0-4.655-4.659,4.727,4.727,0,0,0,1.412,3.367l-2.1,10.462A13.479,13.479,0,0,0,80.05,81.87l-6.4-5.712A6.129,6.129,0,1,0,71.7,78.443L77.677,83.7a13.456,13.456,0,0,0,.691,19.991l-5.316,5.622a5.948,5.948,0,0,0-3.394-1.022,6.163,6.163,0,1,0,6.156,6.162,6.343,6.343,0,0,0-.721-2.916l5.826-6.193a13.464,13.464,0,0,0,16.1-2.946l11.022,7.966a7.77,7.77,0,0,0-1.2,4.118,7.658,7.658,0,1,0,15.316,0A7.817,7.817,0,0,0,114.406,106.791Zm0,0" transform="translate(13 9.671)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{opacity:0;fill:url(#a);}.b{fill:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient><linearGradient id="b" x1="0.337" x2="1" xlink:href="#a"/></defs><g transform="translate(-204.426 -230.797)"><rect class="a" width="68" height="68" transform="translate(204.426 230.797)"/><g transform="translate(209.658 232.191)"><path class="b" d="M25.52,64.045c-1.725-.852-8.6-4.486-10.846-5.656-2.309-1.207-3.3-1.01-5.09.146L6.346,60.67,0,46.383s6.887-3.254,10.033-4.508C15,39.885,17.273,41.6,20.115,43.4c1.209.762,5.131,3.664,5.131,3.664a17.886,17.886,0,0,0,7.783,2.316c5.928,0,6.975.344,6.975,2.266,0,2.113-3.859,2.266-3.883,2.266H26.605c-3.236,0-7.766-1.893-7.766-1.893s3.846,4.156,7.766,4.156h9.547c2.105-.047,6.1-1.047,6.1-4.537,0-4.529-4.066-4.529-9.219-4.529a5.2,5.2,0,0,1-1.127-.145c.2-.1.4-.207.639-.35.9-.523,2.145-1.27,3.535-2.158,3.67-2.3,5.555-2.592,7.387-.152a5.718,5.718,0,0,1,4.248-1.678c1.551,0,2.865,1.039,2.494,2.719,3.975-2.377,5.936-1.42,6.809-.266,1.156,1.527.373,3.109-2.143,4.926C53.244,51.17,37.809,61.543,35.635,62.82c-1.732,1-3.326,2.395-5.8,2.395A9.825,9.825,0,0,1,25.52,64.045ZM22.51,39.5l-.229-.865a.706.706,0,0,1,.129-.607.688.688,0,0,1,.557-.275H35.734a.689.689,0,0,1,.547.275.7.7,0,0,1,.121.607l-.219.865a7.065,7.065,0,0,1-13.674,0Zm6.84,2.486a4.265,4.265,0,0,0,3.178-1.424H26.174A4.239,4.239,0,0,0,29.35,41.982Zm-6.285-5.07a.885.885,0,1,1,0-1.77H35.658a.885.885,0,0,1-.008,1.77Zm-.189-2.637a.7.7,0,0,1-.707-.7V31.021a.565.565,0,0,0-.244-.461,13.168,13.168,0,1,1,14.844,0,.563.563,0,0,0-.242.461v2.547a.7.7,0,0,1-.7.707Zm8.672-8.785a6.207,6.207,0,0,0,2.455-.3c.547-.258.721-.676.721-1.572V14.719H33.059v8.887c0,.219-.1.281-.334.3-.234,0-1.033,0-1.732-.039A6.217,6.217,0,0,1,31.547,25.49Zm-6.18-2.166c0,1.535.463,1.967,1.969,1.967h1.7c1.285,0,1.717-.516,1.877-2.174a4.544,4.544,0,0,1-1.443-.607c-.062,1.141-.145,1.361-.586,1.361H27.557c-.494,0-.578-.055-.578-.562V20.117h1.475a3.131,3.131,0,0,1-.213,1.223.374.374,0,0,1-.334.131,6.154,6.154,0,0,1-.836-.047,3.419,3.419,0,0,1,.41,1.4,8.144,8.144,0,0,0,1.3-.045,1.284,1.284,0,0,0,.844-.455c.281-.35.395-1.223.465-3.107l.016-.2.744-.707v4.154h1.619V15.793H30.848V18.17a28.18,28.18,0,0,0-2.326-2.758c.084-.158.152-.328.221-.486l-1.535-.479a9.09,9.09,0,0,1-3.215,3.9,7.919,7.919,0,0,1,1.2,1.27l.174-.129Zm.906-4.643a11.211,11.211,0,0,0,1.465-1.855c.518.609,1.049,1.27,1.469,1.855Zm17.676-2.123a1.606,1.606,0,0,1,1.186-1.943l2.363-.578a1.608,1.608,0,0,1,.76,3.125l-2.369.576a1.629,1.629,0,0,1-.383.047A1.611,1.611,0,0,1,43.949,16.559ZM12.631,17.631,10.389,16.7a1.608,1.608,0,0,1,1.23-2.971l2.242.941a1.6,1.6,0,1,1-1.23,2.963Zm4.088-9.514L15.328,6.125a1.605,1.605,0,0,1,2.637-1.832l1.391,1.99a1.6,1.6,0,0,1-.4,2.234,1.58,1.58,0,0,1-.916.289A1.6,1.6,0,0,1,16.719,8.117Zm22.709.32a1.614,1.614,0,0,1-.273-2.252l1.488-1.914A1.6,1.6,0,1,1,43.174,6.24L41.686,8.16a1.626,1.626,0,0,1-2.258.277ZM27.746,4.043V1.6a1.607,1.607,0,0,1,3.215,0V4.043a1.607,1.607,0,0,1-3.215,0Z" transform="translate(0 0)"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 3.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M43.013,57.336h-.255l-.074,0a14.064,14.064,0,0,1-8.911-3.467,6.216,6.216,0,0,1,6.1-5.029h6.278a6.218,6.218,0,0,1,6.1,5.03A14.073,14.073,0,0,1,43.6,57.324h-.009l-.067,0H43.5l-.063,0h-.424ZM30.159,54.9H8.5a1.717,1.717,0,0,1-1.715-1.716v-10.1A1.717,1.717,0,0,1,8.5,41.363H20.6a1.717,1.717,0,0,0,1.716-1.715V37.73H11.824a1.717,1.717,0,0,1-1.716-1.715V8.8a1.718,1.718,0,0,1,1.716-1.716h8.768V3.437A3.44,3.44,0,0,1,24.029,0h6.93A3.441,3.441,0,0,1,34.4,3.437V7.089H42.87A1.718,1.718,0,0,1,44.586,8.8V26.022c-.515-.046-1.044-.07-1.574-.07A17.327,17.327,0,0,0,30.157,54.9Zm4.219-36.07a3.437,3.437,0,1,0,3.438,3.437A3.441,3.441,0,0,0,34.378,18.828Zm-13.619,0A3.437,3.437,0,1,0,24.2,22.265,3.441,3.441,0,0,0,20.758,18.828ZM24.029,3.437V7.083h6.924V3.437Zm7.256,47.59v0a14.059,14.059,0,1,1,23.456,0,9.508,9.508,0,0,0-8.589-5.455H44.686a7.193,7.193,0,1,0-3.347,0H39.873a9.5,9.5,0,0,0-8.587,5.457ZM43.013,42.5a3.923,3.923,0,1,1,3.923-3.924A3.928,3.928,0,0,1,43.013,42.5ZM6.844,31.07a1.717,1.717,0,0,1-1.716-1.715V15.176a1.715,1.715,0,1,1,3.431,0V29.355A1.717,1.717,0,0,1,6.844,31.07ZM49.8,27.327h0a17.187,17.187,0,0,0-3.429-1.051v-11.1a1.715,1.715,0,1,1,3.431,0v12.15Zm3.406-.007a1.717,1.717,0,0,1-1.715-1.715V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,53.206,27.32Zm-51.491,0A1.717,1.717,0,0,1,0,25.605V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,1.715,27.32Z" transform="translate(-14477.664 23050.15)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{stroke:#707070;stroke-width:3.75px;opacity:0;fill:url(#a);}.b{fill:url(#b);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient><linearGradient id="b" x1="0.414" x2="1" xlink:href="#a"/></defs><g transform="translate(-2.29 3.525)"><g class="a" transform="translate(2.29 -3.525)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M36.066,58.469a15.431,15.431,0,0,1,0-21.866,15.011,15.011,0,0,1,3.577-2.662,2.018,2.018,0,0,1,1.878,3.571,11.53,11.53,0,0,0-2.6,1.947A11.446,11.446,0,0,0,55.132,55.622a11.938,11.938,0,0,0,1.878-2.462A2.02,2.02,0,1,1,60.5,55.2,15.711,15.711,0,0,1,58,58.469a15.533,15.533,0,0,1-21.929,0Zm-5.87-.994H5.225A5.225,5.225,0,0,1,0,52.263V13.925A5.226,5.226,0,0,1,5.225,8.712H53.769A5.226,5.226,0,0,1,59,13.925V32.117A19.526,19.526,0,0,0,30.2,57.474v0ZM21.753,18.77l-8.5,7.4a2.531,2.531,0,0,0-.239,3.565,2.536,2.536,0,0,0,3.568.239l6.835-5.958L28.446,28.4a2.52,2.52,0,0,0,3.351-.015L42.282,19a2.508,2.508,0,0,0,.191-3.557,2.529,2.529,0,0,0-3.567-.192L30.085,23.14l-5-4.369a2.544,2.544,0,0,0-3.335,0ZM47.03,49.554a2.017,2.017,0,0,1-2.022-2.017V34.091a2.021,2.021,0,0,1,2.022-2.017A15.485,15.485,0,0,1,62.537,47.537a2.018,2.018,0,0,1-2.024,2.017Zm2.025-4.034h9.258a11.471,11.471,0,0,0-9.258-9.229ZM7.53,5.051a2.521,2.521,0,1,1,0-5.043H50.681a2.521,2.521,0,1,1,0,5.043Z" transform="translate(6.296 0.013)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="273" height="323" viewBox="0 0 273 323"><image width="273" height="323" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAiIAAAKGCAYAAAB3OfDSAAAgAElEQVR4nOy9abMlO3YdtpDDme5YVW/ufv16YLNp0gzJCsuOsBz+YDkUIf1ef/QnR9AWJYeowSRlNalmz/3mV1V3OFMmHBsJZO7cB8jhDLdu3cKuypsnkUgkcgIW1h6g/ve/1IgSJcrTk6IElAKuFsDH19qsabtKV0hUtc3FbmcAJgCeAfgMwI8B/ATADwB8YtOvAJwBmNFhANYA7gG8BvBSa3wB4HcAfgHg7zXwdxr4Qmvcao01tNbU8tCfUgO6BEpU66qOGjdL4OsbhZulMvnSJL6kUaI8RcniU40SJQoTAhXXAD6woINAyGca+CGA7yngQ9qvgUsAc1Xlhx3OrLXGjQJea21ACi1TAitaGcDyGwB/AAxIuYs3PUqUKIhAJEqUKEI+BfCPAPwPAP5Ua8OCXGrgwgALhQVvNxyfSoyFBiZa47lhTLQBMj/WwJ+piiX5yjAjGv8OwP8D4G8A3MSbHyVKlAhEokSJkgL4yKph/lxr/BMLRH5qWY1KlF2aFVqKXV0tmnZrzIkxIWCimwN+ZlmWj1S1/lvLkty+808gSpR3WCIQiRIlCgGQ/wXA/6Q1/rwkkKDxoSK1ikJlS4IKTKgAELEYBGUCKF3Ze7idpQMoGh8rpUlV82Ol8N8D+L+0xv8B4D9C4Q7RXC1KlHdSIhCJEuXdlbm1AflnWuNfEAuiNT7VyoKIBLVBaw1AxFpb8GCwhqpAiLbAoyxR79S6Vt88B6lvFH6oYNQ4U6vu+U9WfRPhSJQo75hEIBIlyjsmzjNGA38CjX+lgX+uNf5Mk4GqtvsZAJELOCPCAIkFGoYNUQHQorUynjFaYaqAP1dKX5IBrNbG+PXfQOH3EYxEifJuSQQiUaK8e0IeLH+sNf65Bv4l2YToih0xQrghsWyIWZIqMelhRErLiMAxIUnljkvr0rrlOrBigcsCCv9NooxnTQJlTvEXAD6P72SUKO+ORCASJco7JlrjR4D+lwD+VanVP9KVGy5U0jAZnYtgRAwW0UBiQUYrjxJl2jS4+CFaEYD5LFH6Xygg1Rp3SuEvofBtfC+jRHk3JAKRKFGeuOjGvZa+9w808E+h8b9qjf+u1DgHAwkcMCi004kZ2QEirHxjE2JVO0rXeGNHeLplRlIofKoU/mcAXxvD1crFN8YaiRLlHZAIRKJEeeJCnX1BkVY1XiSVZwyBEHLTvdC6HV21lw0RKhqtG01MbVsiAIzSAuCwtTNkLao8nyml/7dEGw+arwH11/HdjBLl6UsEIlGivAOiNTKt8X0N/LOyNN4xLyQI6ZLELs5+pGUjUjYMRzHyVipu6KqQK4U/KRW+1MBfa43flxqvtMY2vqNRojxdiUAkSpTHKQMhQqe4WGKEId7XGn9awqhjfqS1mlQGHeJETtci2A0nNSti533hRqhgDEhQLxMQ400Dc+y0UPgjKP0/augvAPUfFPCNK/5Y9yRKlCiPRyIQiRLliUrtTqtxpjV+Co1/rDV+WJaYMayxl5ykN7cGrFB4rhT+aaLw+2mGXxc5vtls6yxHQSNRokR5PBLns4wS5TSiDlz2lea8DdvxPoB/Umr8k0KrD0pdzWbbe5a2q209U25pDVPNUnu/tGOJuPVgUU2ckaLAeVGq/zZN8I8WE/3xYqKRp7oOlHYgFnlTzyVKlCgBiYxIlChPTBzIyBJgkkHNJ/ggTfBnZYmfamBKACIZOASpQ7fbDWUtU1vGqmVjtKoFWyK3e89XgRkKX3KdJvhsmuPTosT1coPXKBxhEiVKlKckEYhEiTJMTt3/HbN8TR36LAcu5np+McdHWaJ/VGgTwTTRlhGR7IU1GG3tA2M23LosRLRUwZoctFh7EdootSYm54+Uwo+UUj9ns/Uek50Yq2Uae95okxIlSo9EIBIlyhMTraFJMZOlyOYTPJ9NzGy3z7clMl22r1XLpbErMaJsZFQFFiNEhm1nbrycIdkBO06tM4ApsfPUnGuFH1IANg0T+v2m45AoUaK8pRKBSJR3XU7FdOxb7qHHOU8Z6voXSmly2f0UWl1UAccUs8ewBxBwSBhogGBCWBh3SAChmzxdzIjXloSdT+aFAUPqHNCfao0fmBl629cqJwAeK5qVNUZOxaBE5iTKOysRiESJ8rSk7vg0cFZqfFIW+Ijml3EdfMJAQ81sWEBSqsbfl6b0T5iLbsvVV3SbWgAN87u0C9CmQXSbeSnRLLwuiubESfChBj4EzAy9TqKZSJQoT0giEIny1OXYndbY8k6VXzICSu7RGnOtTfyQ98lkpDVBnf2hArYgBBCS0s6uq+zEdcxSVKn2ca4cXQowss9SOjsRTFDi/bK6hnpSvsA9kmnHZhjGMijHZk4iYxLlyUoEIlGiPA45hSpnojWuyhKXGpgYbxm0IYxkSWBn0SUQUibNCVQpApsJ4KI8qhjDsDDgUzI1TE1/lP4u1oIcpRUuAFzRtexx/V1yqGonSpQoR5IIRKK87XIsxuPUzMWh+2WHqXr2k+S6CmZGS+5UL6rp6GsAUhunwoIQ1YANM1dM0swZ45OSMyIem49eZsQdwxgVVOXNzcR8Foioppp99+dY+8fKUObkWIxJBFJR3nqJQCRKlLdD9gE0Galkykotk2o3I66z9dCNXQiRH9qFbRcsiFnK3XDvXLzGqiIOiQMkNUsijGN3yqxWVKspgLTnWofcjyhRojxCiUAkytsiD818HIvJCKXLkfNQ5gMiXyg0mTLgoySVjM7h4ocILxhtC3DMhWIFun3uR1cwsZYHjnDn9bIi0sXXw6S4gsuq7gmbv8Z3zcIxeW+mZGz6WDk2YxJtS6K89RKBSJQob0b6gEpo20lfbFRltSptI1T7g6Mb4ynDGQ/VrMHYEfQwIm6t4QcfrQisuqlPzZyUgTgjpfe+hO5HCFj0SWRQokR5QxKBSJTHJod2CKdmPMYyHaF8fczI0PJDI/XE9P0am7LE2mhCrM7F2H8wQ1RuE5Jw1Yy2IIXyMG8Zn7SAiLI2J7q93oktwgALOEPCbFbssQUzYZHEzLGYjbGMx6mYk4diTCJTEuXRSAQiUaIcV4YyGnL/UOATYkJ4utOwUH++pAUltpp7njivF9W2CXFsSL2w/BgCRDi4YGvOkJQin1PLlCzwGVMHFQBWFh/RNRXiWvuAWV96SEKqsMicRIlyZIlAJMqbklMzH6diPPrKkx2eBA4yva+DC+ULdqzW9pRsRDZa40aXuAExI1YlU+tsnCcMRy5g3jGqYUI05Fn8V+UAScm2ue1HGVDdlDs2Ihqq1FSfm1LjNdWfARFfLQ5lKFy+UmwjkD60vGMxJkNVTpEpifLWSQQiUaIcJmOBiwQmcjvEqPSl8/2ZLZeAyMsSeAlgXXunWOWGi+ehVTtyag1UhJ1I51WFgAgkwGDMiFXHgIETLoRDtDJ1/47qb68pCTAiUsaquEIAse/Kj2XEGiXKOysRiEQ5tbwtzMe+5ciOq297KNAYW0+enkKRpwlWpVZflhpfKo17XSORKqsu2126ZtYX2lpjaDHJXUgaL5emrJaHDrP98MYRKRtD2sZWRK+01l+WpfpKAysFpNbxp6s2Q5mIQ5mS0PZQOTaA6WPWIlMS5dFKBCJRonTLPkAABzAfx9jOrLHqfVHic1oSpZdAFTq9Vr0kLGKqaoKdmYKYTUgLiPTYiOwAEbbf58pbckbEedWY6O70D/cAPrfLPYsl0sWIhDrksaqUPqak73mNBTxRoryzEoFIlGPJ2858HJvxGKtiObS+iv1KybxDa7XcFvoPidK/S1P9WlkQ4gKbgduMtDUxrd/ae5K2+IBIiba6ZQeIlIwxacUV0RbE6BsN/Fprs9xZIKIOfNf6AMdY4HAoY3Lo+YcCr2MzJRFYRTmaRCAS5anK0M7q2IzHqQDImG3TWZcltluFV0mBL5XCV4nS99BqLoFI4jxUWAh3x4LUhQ70mvExIk4jtOOeK71qWBFlxYi8Lkv8ugR+o4Fb216VAxmRnSqK9VAA0JfvUMYkSpR3XiIQibKv7DsqfWzMx6kYj32BxMGApO4pNdS2VJsE6qskwX9VCX6stf4BNIVMV+3p/Us2o64DIp65ZYa477ofWqYLRgRs3XjTaANCSmBbQn1Ravyy1OoPxO4AmDmPoAMYjbG2IceyKZHH9dmUHMqUhKSPKYm2JFEeXCIQifK2y7GYj1MxHmMBxtGYEQ2Y0O6FVt+WJf6mhP5UQX8AqCnAVDQMeLgExe1FeOGBbobbgrTSJSDhbrpl27vGrTV0UZb4vAT+odTqcw11twcTMnQ7lG8sU9LHkEg5FdCIEuWtkwhEogyVh2ZADmU+hjIdsgMIzt0SWIf2nyp9+LaqAphprb4rNP5aaf1JovTPgPJK6cRkgAMJci4Z3XjOtC5uJCNSpzEGxAGRmhmpjyN/XcOIfKc1/pOG+k9ak8eMOWsunuFYW4+hgOLQ9LFMx1jvm1MzJdGWJMqDSwQiUd4WORXz4STk1XIo43FsgDJmO7dYYlmU+K0C/gtIRQP9EaAvdKlaqhkocXLOkLj0PkaEJWiW4J0UT7ePr9JMJPovSqj/oKH+GsArVBFhtZufT9yLUzEhofR9bUVC5fflj0xJlCcvEYhEkfK2MR99KhXZscsGfkjIdF85ofSHBizB7fqCNdZFqW6h1S8B/PtE6WcK+k+h9bmyRUnVjHYARNytvt4wyIzwOCJobEOcGLsQXRIj8nUJ9XOt1f+roX5h1TK55xr7gEMoXx8w6Ov4hwKDsQDiTTElISbkVLYkEVBLine truncated

Before

Width:  |  Height:  |  Size: 193 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="727" height="727" viewBox="0 0 727 727"><defs><style>.a{fill:url(#a);}.b{fill:url(#d);}.c,.d,.f{fill:none;}.c{stroke:rgba(32,194,255,0);stroke-width:8px;}.d{stroke:rgba(255,173,32,0.15);stroke-width:5px;stroke-dasharray:7 5;}.e{stroke:none;}.g{filter:url(#e);}.h{filter:url(#b);}</style><linearGradient id="a" x1="0.761" y1="0.205" x2="0.284" y2="0.581" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#ffd2ab"/><stop offset="1" stop-color="#ff7855"/></linearGradient><filter id="b" x="88.068" y="60.324" width="217.004" height="181.59" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="c"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><linearGradient id="d" x1="0.237" y1="0.761" x2="0.718" y2="0.394" xlink:href="#a"/><filter id="e" x="424.041" y="484.359" width="215.309" height="181.689" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="f"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter></defs><g transform="translate(4 4)"><g transform="translate(-126.998 -127.002)"><g class="h" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="a" d="M18115.566-21172.494q4.919-8.443,10.389-16.543a294.531,294.531,0,0,1,35.713-43.289,294.545,294.545,0,0,1,43.293-35.717,292.5,292.5,0,0,1,49.682-26.969,290.614,290.614,0,0,1,31.271-11.162l1.656,5.506a288.092,288.092,0,0,0-166.973,131.084Z" transform="translate(-18005 21389)"/></g><g class="g" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="b" d="M18451.539-20750.967a288.209,288.209,0,0,0,165.279-131.172l5.029,2.92q-5.1,8.815-10.8,17.258a294.659,294.659,0,0,1-35.717,43.287,294.647,294.647,0,0,1-43.293,35.717,292.2,292.2,0,0,1-49.686,26.971,291.1,291.1,0,0,1-29.178,10.537Z" transform="translate(-18005 21389)"/></g><circle class="c" cx="359.5" cy="359.5" r="359.5" transform="translate(126.998 127.002)"/></g><g class="d" transform="translate(98 98)"><circle class="e" cx="261.5" cy="261.5" r="261.5"/><circle class="f" cx="261.5" cy="261.5" r="259"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="727" height="727" viewBox="0 0 727 727"><defs><style>.a{fill:url(#a);}.b{fill:url(#d);}.c,.d,.f{fill:none;}.c{stroke:rgba(32,194,255,0);stroke-width:8px;}.d{stroke:rgba(255,173,32,0.15);stroke-width:5px;stroke-dasharray:7 5;}.e{stroke:none;}.g{filter:url(#e);}.h{filter:url(#b);}</style><linearGradient id="a" x1="0.761" y1="0.205" x2="0.284" y2="0.581" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#ffd2ab"/><stop offset="1" stop-color="#ff7855"/></linearGradient><filter id="b" x="88.068" y="60.324" width="217.004" height="181.59" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="c"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><linearGradient id="d" x1="0.237" y1="0.761" x2="0.718" y2="0.394" xlink:href="#a"/><filter id="e" x="424.041" y="484.359" width="215.309" height="181.689" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="7.5" result="f"/><feFlood flood-color="#ff941a" flood-opacity="0.4"/><feComposite operator="in" in2="f"/><feComposite in="SourceGraphic"/></filter></defs><g transform="translate(4 4)"><g transform="translate(-126.998 -127.002)"><g class="h" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="a" d="M18115.566-21172.494q4.919-8.443,10.389-16.543a294.531,294.531,0,0,1,35.713-43.289,294.545,294.545,0,0,1,43.293-35.717,292.5,292.5,0,0,1,49.682-26.969,290.614,290.614,0,0,1,31.271-11.162l1.656,5.506a288.092,288.092,0,0,0-166.973,131.084Z" transform="translate(-18005 21389)"/></g><g class="g" transform="matrix(1, 0, 0, 1, 123, 123)"><path class="b" d="M18451.539-20750.967a288.209,288.209,0,0,0,165.279-131.172l5.029,2.92q-5.1,8.815-10.8,17.258a294.659,294.659,0,0,1-35.717,43.287,294.647,294.647,0,0,1-43.293,35.717,292.2,292.2,0,0,1-49.686,26.971,291.1,291.1,0,0,1-29.178,10.537Z" transform="translate(-18005 21389)"/></g><circle class="c" cx="359.5" cy="359.5" r="359.5" transform="translate(126.998 127.002)"/></g><g class="d" transform="translate(98 98)"><circle class="e" cx="261.5" cy="261.5" r="261.5"/><circle class="f" cx="261.5" cy="261.5" r="259"/></g></g></svg>

Before

Width:  |  Height:  |  Size: 2.2 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="458" height="113.588" viewBox="0 0 458 113.588"><defs><style>.a{opacity:0.78;}.b{fill:url(#a);}.c{fill:#fff;}.d{filter:url(#d);}.e{filter:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#fff"/><stop offset="1" stop-color="#fff9c1"/></linearGradient><filter id="b" x="104.221" y="19.443" width="226.559" height="61.289" filterUnits="userSpaceOnUse"><feOffset dy="1" input="SourceAlpha"/><feGaussianBlur stdDeviation="5.5" result="c"/><feFlood flood-color="#fe0" flood-opacity="0.71"/><feComposite operator="in" in2="c"/><feComposite in="SourceGraphic"/></filter><filter id="d" x="104.221" y="19.443" width="226.559" height="61.289" filterUnits="userSpaceOnUse"><feOffset input="SourceAlpha"/><feGaussianBlur stdDeviation="2" result="e"/><feFlood flood-color="#fff" result="f"/><feComposite operator="out" in="SourceGraphic" in2="e"/><feComposite operator="in" in="f"/><feComposite operator="in" in2="SourceGraphic"/></filter></defs><g transform="translate(-731 -564.412)"><image class="a" width="458" height="113.588" transform="translate(731 564.412)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAADEEAAAMKCAYAAADQmruwAAAgAElEQVR4nOy9W5Mkx3kleDITWZVdfaluNLpxI0EAFEAQ4AUUKRHgVTeOxsZsH+dBL2uyeVrbB/2ctX1aW9u1fZqHfZDt2tiSo5FEzYgakhJJiSAIUCAIEsSlCaIbDTSyMjoz1yIz3DvzeJ763COzquvyHTOgOiP88vk1Itz9O6cz+bO/wGpUzdV+87f53R9Q6PHyzxitt3y916Qzrlb/DvlQNGBL2Dei+/xbodtkN1m2N1zHcHU5q8lyPvE+55drRyF63dXhx41d6v7RRLepoEcB/D6A3wPwOwB2m3vVIVtdd+LbTb6TjPAOh8PhcDgcDofD4XA4HA7HUUansW3ULHgOm7WvsJjbubNGN1vo3G7W67rNvakoW4jXa/7rLlyfNn9voY9Xgd4/Y7D7Cra6N4D+WKS3Kv1ps1Y3av6eZIR2GjftU+1T9ycBoX1DG99uyr6wJsv7Egs9ucaWuB/RdMnRh0347eV0R008uXxP6XO+Zvx9MW3Sn+ryCXtGYtk6li+zPDG/vcz4AaFeJ8JOme509X3az+B6Vds/ENe5X6jyWdtKyr6IUI+qPqqmvP3mr+o3Yv8t6Xecv9X/1dZKqIc9cT9A5L//ttfUtovsi/XB9op+GiD7q8q/ZT3v3y+mGDXtm7QnlUPWW+hfeyJ8uC/GfTIvhX64TfbS/JfUA6dL6cTre9Nlu0R9qnpQ9gfIccHhaXya/ciat43+kTyPKR9VXyp8jCfqheshtnPmuJL9LqvfT5vr0+L6VP0t1o/Vbwhy/g7XzzQX9pbtCWC7wvy3lbwf0PMp/MMoD8gu872E0rfqN7muwM8h1T4x31De6XI4iqdgltN6f0Pe9YiF5/A7r98DVL2F9+Y8jCfTeH6Cz1OMxfxq3Qe9H4RzLUl49R5hHUPoGukKO/mciBVPwSq3ssustxmmd+plTbtjOKu++HmaWb9JPOqwsrxWxxb2cH2MKd8enVvi+wj3c8sDym9I4cWADXbEL3tR/hgupEvpFY9Do556dH9M6cwxTcoZ7czsN/K3gWgvluMl9U8Tt1nfArF/WwFF/+J65HN0XG+qPVW5k/ui/HG8kXkxPfMDcf98pH3Gg0v2GxqPveZ5Wz+LsKpdMs8VJv1bjQcuB+cT0rPsD8hd8KD+IR/4ap6y4lvhLLuzP/gy0wnlsOzgcDOE9bBxfB+rxLjuW+c/+bwro7Q9OTzDWKgZS0PyUIVzuv3V5Vo8f1ytmtys9YBcjFcXkzES6U7Itm5v9XWJQnurcH55a/X11MD5n8e/2oRrLsd6DxeCvWTPUjFW9N2K3ycCyB7uLyvbNOS/cI/rfaleRd3Fy6Pm+3Ckx+1kMp9quGjNcO785TeFnY6jgnu8JRx3AWcBPATgGQCfBfDpxgniQvPgP+zNTXeCcDgcDofD4XA4HA6Hw+FwnCSEQ0IVOUEs7tz3m5NcwQGit8+JnUU0ThDVogPEghNEv87rKoDLqKqPAf1r2ML7hYf7bzen0MI6Ydmhp+MDdoK4fcLXJ5UTxEl2/AiYNm07OQXlDf16svDfacB0oZ2np6RfY0U7n9T5OuC09OtFh8jTMnfhFJZ58bl8Wp7HOEXPZB7H02P3fBp9uI1+7wIqnGvOtXSy59/ZAdRq3s58iN5yBigln8wOv+F05/cX37uOchuftvcFx9HAlPrdaXnOOe4+uO85HJ3mffsDAB+e+tpwOByODcOdIByHjVrt4TMAvg7gOQBPAbjSOEA4HA6Hw+FwOBwOh8PhcDgcjs1h0myyjemgV+eO00PVXXBkyMU+YaspKtwH4Ang1i30d29itHcLW93VVFSrGZon8dBSRC6Tt8UsTuEl8y8x7PJ9ZoxPmLiFXctMu50m3Qm2tldvkCfM9JuqB4u5WSko5DK+q3LM0q2ZYJtDAZPTclh8UeFkUZHlJGLRuScoupyGQ6aTBcKlk17mgOmCis1p6de3qV+f5PKGfn3anNYWx/HklLQzK3CdFufTk67AFbBKgevo9+vR3jaq6iMAPtY4WO8sHCC0sOjccxqc1rDwHpI6feQiN54Kp+Mv9sHb0hmkLP8pOVakYzkSRzNTupFfEo6Z8kX8sVA8UOmzfRyP07sTe3yKnEnajt/F95hqxXqIw3GQWHyHrhaeSe78dToR2r3TLCz+GsDPAFw/7RXjcDgcm4Q7QTgOC7WTw4MAnm6cH2oniE81qhAOh8PhcDgcDofD4XA4HA6HY/PoLqg+HBY683Xn6h5U9WGlG/dhsDs/XL/V8kCOw3FyMHUniBMLd4KYw50gTgZWHR50J4iTh9PqBHGbDiaedBw/J4jR3gCYXMb41kdQja8C1YXG1TdfCeI4Kl+sj6N8yJsP728C06X/TOWMzByVc4IZb00nkrxwdTmbdp45ZyyMYytd5XwinDwi6L6sHw5npJundLKgsmYpunQX7WMFwjF6g9XzgbRDpC9/G5BOL1xPAyzZ2bo/WgFU+yzVow6fq7Bj2T9vF9wps9VvhD3Kzjv5ZNqXmW5S3qX7d/per3t74Vqnya8ev4XPJ24Xrn9xXdZHZrhsrIzfWejP09X2lea/crwUhN9UOvv+XujTA2AcH3sd9GbkMG8DeAn9wcs4u/02+oP3Y0wmVQlkLHw/ITFhEpeAEH5v+fdWJcJnYjUZzASjvUlD8jIvb0I6o0hkjHIyVLkleQz2r6+k3tnulfWuleXYDi7fcrjOQjvU70nv4+Vv3VwdweFw7Ad3gnAcBmr1h2cBfAnA8wA+2ThEuAOEw+FwOBwOh8PhcDgcDofDcZgIG3BtGUKLUAFV/d8YGOw0G4NNvmETaSts9vAmHG9e8aYRbeIx4maW2twL6YfrvOnVqNPHzbHmstq8YsRNr73l/BNlCKG4kJSX8me7YnjVrlwPQtEi5hP+wXZTegqJogQj1AsrTIh8onIHtWssx4fL0WJ5eHM4pMPKHiGisEfVs+xX1I536nfuJBTTY2WNzM3oRJGE6jnpJ/Rb1g/3g1AfodxNuKg80qVwS/ndccDaOrM63di+rDhC5Ygg+2I41W5c7nBDKaMYhwd4PuHyg/snVsfjwwjcfiqfaK8YF6D5JJaXyiM3+8V8kIy/WE/Nxn+j7DIP15EKNqpfs+JOzJcPP6hDDNZhkEwlH/U8ifFm6d9RKlL9YIvbhxWPwjiieYmVdlQ9crrJ84LGtzoEEsCHPWL/msWbYqtp33l76+cTRL0zknET8hXPyfib208pIvF421u+D54PluafKbaq5qBWf/lAC/c3NU/JQy9GvOT5PaFw/N7CsPp5sG/lc+YOY/6oObQU04OIz/61mc8va7yrccvjU+YfxgnPH0vPqSlGzaGlLXFoST035fwhDpfFdLF8P3fe4/rcoveeZL5eyrfTKG7V/WeycFhrrty2eOiK31u5/464XOJQV/I+p+Yz9T4xu96dfTQMb+ygGp8Bqn5zrdN8x6SH3cdUT5FJP/zmcGRHDG/03yQcHUq14qv0Asz4wm5wuSg9tjspRyIpJ+wbinDhPpmb5NuMN0vLQ7afyF/Nj1a75rZ7TF+V36pPftAmE6thz2L5RtM0PNsl2jMbqwUcU/sDrPyM+2Y7hHHW3B+r9FS9by0fsi9u98J5ojWWxts0GdfJOLPWN6zrm7rfwJxnOD8uR3ealU+C3P6+6XA8LwQsxZsu9btZXXQX77Vor03hsPIJ6JKzS2G+piCpeh4Line truncated

Before

Width:  |  Height:  |  Size: 625 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{opacity:0;fill:url(#a);}.b{fill:url(#b);}</style><linearGradient id="a" x1="0.5" x2="0.5" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient><linearGradient id="b" x1="0.405" x2="1" xlink:href="#a"/></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M110.023,105.37H98.2a1.721,1.721,0,0,1-1.716-1.716v-1.918h10.189a1.721,1.721,0,0,0,1.716-1.716V72.8a1.721,1.721,0,0,0-1.716-1.716H98.2V67.437A3.444,3.444,0,0,0,94.76,64H87.83a3.444,3.444,0,0,0-3.437,3.437v3.652H75.625A1.721,1.721,0,0,0,73.91,72.8v27.21a1.721,1.721,0,0,0,1.716,1.716h10.49v1.918a1.721,1.721,0,0,1-1.716,1.716H72.3a1.721,1.721,0,0,0-1.716,1.716v10.1A1.721,1.721,0,0,0,72.3,118.9h37.724a1.721,1.721,0,0,0,1.716-1.716v-10.1A1.726,1.726,0,0,0,110.023,105.37Zm-8.406-19.1a3.437,3.437,0,1,1-3.437-3.437A3.436,3.436,0,0,1,101.616,86.266ZM87.83,67.437h6.924v3.646H87.83ZM81.121,86.266A3.437,3.437,0,1,1,84.558,89.7,3.436,3.436,0,0,1,81.121,86.266Zm32.48-7.089V93.355a1.716,1.716,0,0,1-3.431,0V79.177a1.716,1.716,0,0,1,3.431,0Zm5.122,3.548v6.881a1.716,1.716,0,0,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0ZM70.644,95.07a1.717,1.717,0,0,1-1.716-1.716V79.177a1.716,1.716,0,0,1,3.431,0V93.355A1.713,1.713,0,0,1,70.644,95.07ZM67.231,82.724v6.881a1.716,1.716,0,1,1-3.431,0V82.724a1.716,1.716,0,0,1,3.431,0Zm0,0" transform="translate(-14540.154 22987.455)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="188" height="241" viewBox="0 0 188 241"><defs><style>.a{fill:url(#a);}.b{fill:#fff;opacity:0.47;}</style><pattern id="a" preserveAspectRatio="xMidYMid slice" width="100%" height="100%" viewBox="0 0 376 482"><image width="376" height="482" xlink:href="data:image/png;base64,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 truncated

Before

Width:  |  Height:  |  Size: 68 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;stroke:#707070;stroke-width:3.75px;opacity:0;}.b{fill:url(#a);}.c{stroke:none;}.d{fill:none;}</style><linearGradient id="a" x1="0.431" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(-71.077 -67.746)"><g class="a" transform="translate(71.077 67.746)"><rect class="c" width="68" height="68"/><rect class="d" x="1.875" y="1.875" width="64.25" height="64.25"/></g><path class="b" d="M114.406,106.791a7.707,7.707,0,0,0-4.354,1.353L98.7,99.937a13.3,13.3,0,0,0,1.742-6.583c0-.421-.03-.842-.06-1.263L112,85.207a4.687,4.687,0,1,0-1.952-2.345L99.691,88.995a13.678,13.678,0,0,0-6.1-7.365l2.072-10.341c.15,0,.3.03.451.03a4.66,4.66,0,1,0-4.655-4.659,4.727,4.727,0,0,0,1.412,3.367l-2.1,10.462A13.479,13.479,0,0,0,80.05,81.87l-6.4-5.712A6.129,6.129,0,1,0,71.7,78.443L77.677,83.7a13.456,13.456,0,0,0,.691,19.991l-5.316,5.622a5.948,5.948,0,0,0-3.394-1.022,6.163,6.163,0,1,0,6.156,6.162,6.343,6.343,0,0,0-.721-2.916l5.826-6.193a13.464,13.464,0,0,0,16.1-2.946l11.022,7.966a7.77,7.77,0,0,0-1.2,4.118,7.658,7.658,0,1,0,15.316,0A7.817,7.817,0,0,0,114.406,106.791Zm0,0" transform="translate(13 9.671)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

@@ -1,13 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68">
<defs>
<linearGradient id="ap-idea" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f3212c"/>
<stop offset="1" stop-color="#aa071a"/>
</linearGradient>
</defs>
<g fill="url(#ap-idea)" transform="translate(12 10)">
<path d="M22 2.2A12.8 12.8 0 0 0 9.2 15c0 5.1 2.9 9.5 7.1 11.6v3.8a2.4 2.4 0 0 0 2.4 2.4h6.6a2.4 2.4 0 0 0 2.4-2.4v-3.8A12.8 12.8 0 0 0 34.8 15 12.8 12.8 0 0 0 22 2.2Zm3.3 26.8h-6.6v-2.1h6.6Zm-3.3-26.8A10.4 10.4 0 0 1 32.4 15a10.4 10.4 0 0 1-6.3 9.5 2.4 2.4 0 0 0-1.3 2.1v.3h-5.6v-.3a2.4 2.4 0 0 0-1.3-2.1A10.4 10.4 0 0 1 11.6 15 10.4 10.4 0 0 1 22 2.2Z"/>
<path d="M17.6 39.2a2 2 0 0 0 2 2h4.8a2 2 0 0 0 2-2v-1.4h-8.8Zm-1.8-3.8h12.4a1.6 1.6 0 1 0 0-3.2H15.8a1.6 1.6 0 1 0 0 3.2Z"/>
<path d="M8.4 22.6a1.6 1.6 0 0 0 0-3.2H3.8a1.6 1.6 0 1 0 0 3.2Zm31.8 0a1.6 1.6 0 0 0 0-3.2h-4.6a1.6 1.6 0 1 0 0 3.2ZM7.2 10.8a1.6 1.6 0 0 0 2.3-2.3L6.2 5.3A1.6 1.6 0 0 0 4 7.6Zm29.3-2.3a1.6 1.6 0 0 0 2.3 2.3l3.2-3.2A1.6 1.6 0 1 0 39.7 5.3Z"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68"><defs><style>.a{fill:#fff;opacity:0;}.b{fill:url(#a);}</style><linearGradient id="a" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox"><stop offset="0" stop-color="#f3212c"/><stop offset="1" stop-color="#aa071a"/></linearGradient></defs><g transform="translate(14482.893 -23044.904)"><rect class="a" width="68" height="68" transform="translate(-14482.893 23044.904)"/><path class="b" d="M43.013,57.336h-.255l-.074,0a14.064,14.064,0,0,1-8.911-3.467,6.216,6.216,0,0,1,6.1-5.029h6.278a6.218,6.218,0,0,1,6.1,5.03A14.073,14.073,0,0,1,43.6,57.324h-.009l-.067,0H43.5l-.063,0h-.424ZM30.159,54.9H8.5a1.717,1.717,0,0,1-1.715-1.716v-10.1A1.717,1.717,0,0,1,8.5,41.363H20.6a1.717,1.717,0,0,0,1.716-1.715V37.73H11.824a1.717,1.717,0,0,1-1.716-1.715V8.8a1.718,1.718,0,0,1,1.716-1.716h8.768V3.437A3.44,3.44,0,0,1,24.029,0h6.93A3.441,3.441,0,0,1,34.4,3.437V7.089H42.87A1.718,1.718,0,0,1,44.586,8.8V26.022c-.515-.046-1.044-.07-1.574-.07A17.327,17.327,0,0,0,30.157,54.9Zm4.219-36.07a3.437,3.437,0,1,0,3.438,3.437A3.441,3.441,0,0,0,34.378,18.828Zm-13.619,0A3.437,3.437,0,1,0,24.2,22.265,3.441,3.441,0,0,0,20.758,18.828ZM24.029,3.437V7.083h6.924V3.437Zm7.256,47.59v0a14.059,14.059,0,1,1,23.456,0,9.508,9.508,0,0,0-8.589-5.455H44.686a7.193,7.193,0,1,0-3.347,0H39.873a9.5,9.5,0,0,0-8.587,5.457ZM43.013,42.5a3.923,3.923,0,1,1,3.923-3.924A3.928,3.928,0,0,1,43.013,42.5ZM6.844,31.07a1.717,1.717,0,0,1-1.716-1.715V15.176a1.715,1.715,0,1,1,3.431,0V29.355A1.717,1.717,0,0,1,6.844,31.07ZM49.8,27.327h0a17.187,17.187,0,0,0-3.429-1.051v-11.1a1.715,1.715,0,1,1,3.431,0v12.15Zm3.406-.007a1.717,1.717,0,0,1-1.715-1.715V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,53.206,27.32Zm-51.491,0A1.717,1.717,0,0,1,0,25.605V18.724a1.715,1.715,0,0,1,3.431,0v6.881A1.717,1.717,0,0,1,1.715,27.32Z" transform="translate(-14477.664 23050.15)"/></g></svg>

Before

Width:  |  Height:  |  Size: 1.9 KiB

@@ -1,14 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="68" height="68" viewBox="0 0 68 68">
<defs>
<linearGradient id="ap-task" x1="0.405" x2="1" y2="1" gradientUnits="objectBoundingBox">
<stop offset="0" stop-color="#f3212c"/>
<stop offset="1" stop-color="#aa071a"/>
</linearGradient>
</defs>
<g fill="url(#ap-task)" transform="translate(14 12)">
<path d="M28.4 2.2H15.6A3.4 3.4 0 0 0 12.2 5.6v2.8H8.6A3.4 3.4 0 0 0 5.2 11.8v28.8A3.4 3.4 0 0 0 8.6 44h22.8a3.4 3.4 0 0 0 3.4-3.4V11.8a3.4 3.4 0 0 0-3.4-3.4h-3.6V5.6A3.4 3.4 0 0 0 28.4 2.2Zm-12.8 3.4h12.8v2.8H15.6Zm19.2 35.8H8.6V11.8h3.6v2.2a1.6 1.6 0 0 0 1.6 1.6h12.8a1.6 1.6 0 0 0 1.6-1.6v-2.2h3.6Z"/>
<rect x="11.4" y="24.2" width="3.6" height="11.6" rx="1.2"/>
<rect x="18.2" y="20.4" width="3.6" height="15.4" rx="1.2"/>
<rect x="25" y="27.2" width="3.6" height="8.6" rx="1.2"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 924 B

@@ -18,9 +18,7 @@ import {
} from "lucide-react";
import type { ComponentProps, HTMLAttributes, ReactElement } from "react";
import { createContext, memo, useContext, useEffect, useState } from "react";
import type { StreamdownProps } from "streamdown";
import { SafeStreamdown } from "@/core/streamdown";
import { Streamdown } from "streamdown";
export type MessageProps = HTMLAttributes<HTMLDivElement> & {
from: UIMessage["role"];
@@ -304,11 +302,11 @@ export const MessageBranchPage = ({
);
};
export type MessageResponseProps = StreamdownProps;
export type MessageResponseProps = ComponentProps<typeof Streamdown>;
export const MessageResponse = memo(
({ className, ...props }: MessageResponseProps) => (
<SafeStreamdown
<Streamdown
className={cn(
"size-full [&>*:first-child]:mt-0 [&>*:last-child]:mb-0",
className,
@@ -34,14 +34,9 @@ import {
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import type { PromptInputFilePart, UploadPolicy } from "@/core/uploads";
import {
DEFAULT_UPLOAD_POLICY,
splitUnsupportedUploadFiles,
useUploadPolicy,
validateChatUploadFiles,
} from "@/core/uploads";
import { imeEnterAction } from "@/lib/ime";
import type { PromptInputFilePart } from "@/core/uploads";
import { splitUnsupportedUploadFiles } from "@/core/uploads";
import { isIMEComposing } from "@/lib/ime";
import { cn } from "@/lib/utils";
import type { ChatStatus } from "ai";
import {
@@ -61,12 +56,11 @@ import {
type ChangeEventHandler,
Children,
type ClipboardEventHandler,
type ComponentProps,
type CompositionEventHandler,
createContext,
type FormEvent,
type FormEventHandler,
type HTMLAttributes,
type ComponentProps,
createContext,
type FormEvent,
type FormEventHandler,
type HTMLAttributes,
type KeyboardEventHandler,
type PropsWithChildren,
type ReactNode,
@@ -129,11 +123,11 @@ export const usePromptInputController = () => {
return ctx;
};
// Optional variants (do NOT throw). Useful for dual-mode components and for
// Fast Refresh transitions where a page can briefly retain the previous
// provider context instance.
export const useOptionalPromptInputController = () =>
useContext(PromptInputController);
// Optional variants (do NOT throw). Useful for dual-mode components and for
// Fast Refresh transitions where a page can briefly retain the previous
// provider context instance.
export const useOptionalPromptInputController = () =>
useContext(PromptInputController);
export const useProviderAttachments = () => {
const ctx = useContext(ProviderAttachmentsContext);
@@ -151,7 +145,6 @@ const usePromptInputValidation = () => useContext(PromptInputValidationContext);
export type PromptInputProviderProps = PropsWithChildren<{
initialInput?: string;
uploadPolicy?: UploadPolicy;
}>;
/**
@@ -160,12 +153,8 @@ export type PromptInputProviderProps = PropsWithChildren<{
*/
export function PromptInputProvider({
initialInput: initialTextInput = "",
uploadPolicy,
children,
}: PromptInputProviderProps) {
const { data: fetchedUploadPolicy } = useUploadPolicy();
const effectiveUploadPolicy =
uploadPolicy ?? fetchedUploadPolicy ?? DEFAULT_UPLOAD_POLICY;
// ----- textInput state
const [textInput, setTextInput] = useState(initialTextInput);
const clearInput = useCallback(() => setTextInput(""), []);
@@ -174,7 +163,6 @@ export function PromptInputProvider({
const [attachmentFiles, setAttachmentFiles] = useState<
(PromptInputFilePart & { id: string })[]
>([]);
const attachmentsRef = useRef(attachmentFiles);
const fileInputRef = useRef<HTMLInputElement | null>(null);
const openRef = useRef<() => void>(() => {});
@@ -184,26 +172,9 @@ export function PromptInputProvider({
return;
}
const current = attachmentsRef.current;
const existing = current.map((item) => ({
name: item.filename ?? "attachment",
size: item.file?.size ?? 0,
type: item.mediaType ?? "",
}));
const validation = validateChatUploadFiles(
incoming,
existing,
effectiveUploadPolicy,
);
for (const message of new Set(
validation.issues.map((issue) => issue.message),
)) {
toast.error(message);
}
if (validation.accepted.length === 0) return;
const next = current.concat(
validation.accepted.map((file) => ({
setAttachmentFiles((prev) =>
prev.concat(
incoming.map((file) => ({
id: nanoid(),
type: "file" as const,
url: URL.createObjectURL(file),
@@ -211,31 +182,33 @@ export function PromptInputProvider({
filename: file.name,
file,
})),
),
);
attachmentsRef.current = next;
setAttachmentFiles(next);
}, [effectiveUploadPolicy]);
}, []);
const remove = useCallback((id: string) => {
const current = attachmentsRef.current;
const found = current.find((f) => f.id === id);
if (found?.url) URL.revokeObjectURL(found.url);
const next = current.filter((f) => f.id !== id);
attachmentsRef.current = next;
setAttachmentFiles(next);
setAttachmentFiles((prev) => {
const found = prev.find((f) => f.id === id);
if (found?.url) {
URL.revokeObjectURL(found.url);
}
return prev.filter((f) => f.id !== id);
});
}, []);
const clear = useCallback(() => {
for (const f of attachmentsRef.current) {
if (f.url) {
URL.revokeObjectURL(f.url);
setAttachmentFiles((prev) => {
for (const f of prev) {
if (f.url) {
URL.revokeObjectURL(f.url);
}
}
}
attachmentsRef.current = [];
setAttachmentFiles([]);
return [];
});
}, []);
// Keep a ref to attachments for cleanup on unmount (avoids stale closure)
const attachmentsRef = useRef(attachmentFiles);
attachmentsRef.current = attachmentFiles;
// Cleanup blob URLs on unmount to prevent memory leaks
@@ -431,14 +404,14 @@ export function PromptInputAttachments({
return (
<div
className={cn("flex w-full flex-wrap items-center gap-2 p-3", className)}
{...props}
>
{attachments.files.map((file) => (
<div key={file.id} className="max-w-60">
{children(file)}
</div>
))}
</div>
{...props}
>
{attachments.files.map((file) => (
<div key={file.id} className="max-w-60">
{children(file)}
</div>
))}
</div>
);
}
@@ -486,15 +459,8 @@ export type PromptInputProps = Omit<
// Minimal constraints
maxFiles?: number;
maxFileSize?: number; // bytes
uploadPolicy?: UploadPolicy;
onError?: (err: {
code:
| "max_files"
| "max_file_size"
| "max_total_size"
| "unsupported_type"
| "accept"
| "unsupported_package";
code: "max_files" | "max_file_size" | "accept" | "unsupported_package";
message: string;
}) => void;
onSubmit: (
@@ -512,22 +478,11 @@ export const PromptInput = ({
syncHiddenInput,
maxFiles,
maxFileSize,
uploadPolicy,
onError,
onSubmit,
children,
...props
}: PromptInputProps) => {
const { data: fetchedUploadPolicy } = useUploadPolicy();
const effectiveUploadPolicy =
uploadPolicy ?? fetchedUploadPolicy ?? DEFAULT_UPLOAD_POLICY;
const policyAccept = useMemo(
() =>
Object.values(effectiveUploadPolicy.groups)
.flatMap((group) => group.extensions)
.join(","),
[effectiveUploadPolicy],
);
// Try to use a provider controller if present
const controller = useOptionalPromptInputController();
const usingProvider = !!controller;
@@ -562,9 +517,6 @@ export const PromptInput = ({
.filter(Boolean);
return patterns.some((pattern) => {
if (pattern.startsWith(".")) {
return f.name.toLowerCase().endsWith(pattern.toLowerCase());
}
if (pattern.endsWith("/*")) {
const prefix = pattern.slice(0, -1); // e.g: image/* -> image/
return f.type.startsWith(prefix);
@@ -579,67 +531,52 @@ export const PromptInput = ({
(fileList: File[] | FileList) => {
const incoming = Array.from(fileList);
const accepted = incoming.filter((f) => matchesAccept(f));
if (accepted.length < incoming.length) {
const error = {
if (incoming.length && accepted.length === 0) {
onError?.({
code: "accept",
message: "部分文件不符合当前输入框允许的格式。",
} as const;
onError?.(error);
if (!onError) toast.error(error.message);
message: "No files match the accepted types.",
});
return;
}
const localPolicy: UploadPolicy = {
...effectiveUploadPolicy,
max_files_per_message:
typeof maxFiles === "number"
? Math.min(effectiveUploadPolicy.max_files_per_message, maxFiles)
: effectiveUploadPolicy.max_files_per_message,
groups: Object.fromEntries(
Object.entries(effectiveUploadPolicy.groups).map(([key, group]) => [
key,
{
...group,
max_bytes:
typeof maxFileSize === "number"
? Math.min(group.max_bytes, maxFileSize)
: group.max_bytes,
},
]),
) as UploadPolicy["groups"],
};
const existing = items.map((item) => ({
name: item.filename ?? "attachment",
size: item.file?.size ?? 0,
type: item.mediaType ?? "",
}));
const validation = validateChatUploadFiles(
accepted,
existing,
localPolicy,
);
for (const issue of Array.from(
new Map(
validation.issues.map((item) => [item.message, item]),
).values(),
)) {
onError?.({ code: issue.code, message: issue.message });
if (!onError) toast.error(issue.message);
const withinSize = (f: File) =>
maxFileSize ? f.size <= maxFileSize : true;
const sized = accepted.filter(withinSize);
if (accepted.length > 0 && sized.length === 0) {
onError?.({
code: "max_file_size",
message: "All files exceed the maximum size.",
});
return;
}
if (validation.accepted.length === 0) return;
setItems((prev) =>
prev.concat(
validation.accepted.map((file) => ({
setItems((prev) => {
const capacity =
typeof maxFiles === "number"
? Math.max(0, maxFiles - prev.length)
: undefined;
const capped =
typeof capacity === "number" ? sized.slice(0, capacity) : sized;
if (typeof capacity === "number" && sized.length > capacity) {
onError?.({
code: "max_files",
message: "Too many files. Some were not added.",
});
}
const next: (PromptInputFilePart & { id: string })[] = [];
for (const file of capped) {
next.push({
id: nanoid(),
type: "file" as const,
type: "file",
url: URL.createObjectURL(file),
mediaType: file.type,
filename: file.name,
file,
})),
),
);
});
}
return prev.concat(next);
});
},
[effectiveUploadPolicy, items, matchesAccept, maxFiles, maxFileSize, onError],
[matchesAccept, maxFiles, maxFileSize, onError],
);
const removeLocal = useCallback(
@@ -828,17 +765,11 @@ export const PromptInput = ({
event.preventDefault();
const form = event.currentTarget;
// Prefer the live textarea. Firefox 102 applies the chosen candidate to
// the DOM before React state catches up, and a send click in that gap
// would otherwise submit the previous pinyin-less value.
const liveText = form.querySelector<HTMLTextAreaElement>(
"textarea[name='message']",
)?.value;
const text = usingProvider
? (liveText ?? controller.textInput.value)
? controller.textInput.value
: (() => {
const formData = new FormData(form);
return (formData.get("message") as string) || liveText || "";
return (formData.get("message") as string) || "";
})();
// Reset form immediately after capturing text to avoid race condition
@@ -901,7 +832,7 @@ export const PromptInput = ({
const inner = (
<PromptInputValidationContext.Provider value={sanitizeIncomingFiles}>
<input
accept={accept ?? policyAccept}
accept={accept}
aria-label="Upload files"
className="hidden"
multiple={multiple}
@@ -916,12 +847,10 @@ export const PromptInput = ({
ref={formRef}
{...props}
>
{/* Do not rely on InputGroup's :has() selectors here: Chrome versions
before 105 ignore them, keep the horizontal flex layout, and
squeeze the textarea beside the footer controls. */}
<InputGroup className="h-auto min-h-16 flex-col items-stretch">
{children}
</InputGroup>
{/* Do not rely on InputGroup's :has(textarea) selector here: Chrome
versions before 105 ignore :has(), retain h-9, and clip the whole
multi-line composer to a single row. */}
<InputGroup className="h-auto min-h-16">{children}</InputGroup>
</form>
</PromptInputValidationContext.Provider>
);
@@ -948,100 +877,58 @@ export type PromptInputTextareaProps = ComponentProps<
typeof InputGroupTextarea
>;
export const PromptInputTextarea = ({
onChange,
onInput,
onKeyDown,
onCompositionStart,
onCompositionEnd,
className,
placeholder = "What would you like to know?",
defaultValue,
...props
}: PromptInputTextareaProps) => {
const controller = useOptionalPromptInputController();
const attachments = usePromptInputAttachments();
const sanitizeIncomingFiles = usePromptInputValidation();
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
const composingRef = useRef(false);
const compositionEndedAtRef = useRef(0);
const onChangeRef = useRef(onChange);
const onInputRef = useRef(onInput);
const onKeyDownRef = useRef(onKeyDown);
const onCompositionStartRef = useRef(onCompositionStart);
const onCompositionEndRef = useRef(onCompositionEnd);
const setInputRef = useRef(controller?.textInput.setInput);
const attachmentsRef = useRef(attachments);
onChangeRef.current = onChange;
onInputRef.current = onInput;
onKeyDownRef.current = onKeyDown;
onCompositionStartRef.current = onCompositionStart;
onCompositionEndRef.current = onCompositionEnd;
setInputRef.current = controller?.textInput.setInput;
attachmentsRef.current = attachments;
const publishValue = useCallback((value: string) => {
setInputRef.current?.(value);
}, []);
const resizeForLegacyChrome = useCallback((textarea: HTMLTextAreaElement) => {
// Firefox 102 commits an open IME composition as raw pinyin when the
// textarea's height or overflow changes mid-composition.
if (composingRef.current) return;
if (
typeof CSS !== "undefined" &&
typeof CSS.supports === "function" &&
CSS.supports("field-sizing", "content")
) {
return;
}
// Chrome 109 ignores field-sizing: content. Preserve the same 4rem–12rem
// autosize range used by min-h-16/max-h-48 instead of leaving the prompt
// stuck at its minimum height.
textarea.style.height = "auto";
const height = Math.max(64, Math.min(textarea.scrollHeight, 192));
textarea.style.height = `${height}px`;
textarea.style.overflowY = textarea.scrollHeight > 192 ? "auto" : "hidden";
}, []);
// onInput does not run for a controlled value filled by a suggested question
// or restored draft. Resize once after every render in legacy Chrome too.
useEffect(() => {
if (composingRef.current) return;
const textarea = textareaRef.current;
if (!textarea) return;
const frame = window.requestAnimationFrame(() => {
resizeForLegacyChrome(textarea);
});
return () => window.cancelAnimationFrame(frame);
}, [controller?.textInput.value, resizeForLegacyChrome]);
export const PromptInputTextarea = ({
onChange,
onInput,
className,
placeholder = "What would you like to know?",
...props
}: PromptInputTextareaProps) => {
const controller = useOptionalPromptInputController();
const attachments = usePromptInputAttachments();
const sanitizeIncomingFiles = usePromptInputValidation();
const [isComposing, setIsComposing] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement | null>(null);
const resizeForLegacyChrome = useCallback((textarea: HTMLTextAreaElement) => {
if (
typeof CSS !== "undefined" &&
typeof CSS.supports === "function" &&
CSS.supports("field-sizing", "content")
) {
return;
}
// Chrome 109 ignores field-sizing: content. Preserve the same 4rem–12rem
// autosize range used by min-h-16/max-h-48 instead of leaving the prompt
// stuck at its minimum height.
textarea.style.height = "auto";
const height = Math.max(64, Math.min(textarea.scrollHeight, 192));
textarea.style.height = `${height}px`;
textarea.style.overflowY = textarea.scrollHeight > 192 ? "auto" : "hidden";
}, []);
// onInput does not run for a controlled value filled by a suggested question
// or restored draft. Resize once after every render in legacy Chrome too.
useEffect(() => {
const textarea = textareaRef.current;
if (!textarea) return;
const frame = window.requestAnimationFrame(() => {
resizeForLegacyChrome(textarea);
});
return () => window.cancelAnimationFrame(frame);
}, [controller?.textInput.value, resizeForLegacyChrome]);
const handleKeyDown: KeyboardEventHandler<HTMLTextAreaElement> = (e) => {
if (e.key === "Enter") {
const action = imeEnterAction({
isComposing: composingRef.current,
nativeIsComposing: e.nativeEvent.isComposing || e.key === "Process",
keyCode: e.keyCode,
compositionEndedAt: compositionEndedAtRef.current,
now: performance.now(),
});
// Firefox 102 confirms the candidate on this key. preventDefault here
// cancels that confirmation and leaves the pinyin in the box.
if (action === "ignore") {
if (isIMEComposing(e, isComposing)) {
return;
}
onKeyDownRef.current?.(e);
if (e.defaultPrevented || e.shiftKey) {
if (e.shiftKey) {
return;
}
// The confirming Enter already finished the candidate. Swallow it so
// Firefox does not also insert a newline or send the message.
e.preventDefault();
if (action === "swallow") {
return;
}
// Check if the submit button is disabled before submitting
const form = e.currentTarget.form;
@@ -1053,59 +940,22 @@ export const PromptInputTextarea = ({
}
form?.requestSubmit();
return;
}
onKeyDownRef.current?.(e);
if (e.defaultPrevented) return;
if (composingRef.current) return;
// Remove last attachment when Backspace is pressed and textarea is empty
if (
e.key === "Backspace" &&
e.currentTarget.value === "" &&
attachmentsRef.current.files.length > 0
attachments.files.length > 0
) {
e.preventDefault();
const lastAttachment = attachmentsRef.current.files.at(-1);
const lastAttachment = attachments.files.at(-1);
if (lastAttachment) {
attachmentsRef.current.remove(lastAttachment.id);
attachments.remove(lastAttachment.id);
}
}
};
const handleCompositionStart: CompositionEventHandler<HTMLTextAreaElement> = (
event,
) => {
composingRef.current = true;
compositionEndedAtRef.current = 0;
onCompositionStartRef.current?.(event);
};
const handleCompositionEnd: CompositionEventHandler<HTMLTextAreaElement> = (
event,
) => {
onCompositionEndRef.current?.(event);
composingRef.current = false;
compositionEndedAtRef.current = performance.now();
const el = event.currentTarget;
// Firefox 102 dispatches compositionend before the committed candidate is
// visible, and before the input event that carries it. Syncing the
// compositionend value here would write the raw pinyin back over 汉字.
window.setTimeout(() => {
if (el.isConnected) publishValue(el.value);
}, 0);
};
const handleChange: ChangeEventHandler<HTMLTextAreaElement> = (event) => {
// Keep the controlled value identical to the DOM, including the pinyin
// still being composed. Otherwise React restores the previous value at
// the end of the input event and Firefox 102 cannot replace it.
publishValue(event.currentTarget.value);
onChangeRef.current?.(event);
};
const handlePaste: ClipboardEventHandler<HTMLTextAreaElement> = (event) => {
const items = event.clipboardData?.items;
@@ -1135,28 +985,35 @@ export const PromptInputTextarea = ({
}
};
const controlledProps = controller
? {
value: controller.textInput.value,
onChange: (e: ChangeEvent<HTMLTextAreaElement>) => {
controller.textInput.setInput(e.currentTarget.value);
onChange?.(e);
},
}
: {
onChange,
};
return (
<InputGroupTextarea
{...props}
className={cn("field-sizing-content max-h-48 min-h-16", className)}
name="message"
ref={textareaRef}
rows={3}
onChange={handleChange}
onCompositionEnd={handleCompositionEnd}
onCompositionStart={handleCompositionStart}
onKeyDown={handleKeyDown}
onInput={(event) => {
if (!composingRef.current) {
resizeForLegacyChrome(event.currentTarget);
}
onInputRef.current?.(event);
}}
<InputGroupTextarea
className={cn("field-sizing-content max-h-48 min-h-16", className)}
name="message"
ref={textareaRef}
rows={3}
onCompositionEnd={() => setIsComposing(false)}
onCompositionStart={() => setIsComposing(true)}
onKeyDown={handleKeyDown}
onInput={(event) => {
resizeForLegacyChrome(event.currentTarget);
onInput?.(event);
}}
onPaste={handlePaste}
placeholder={placeholder}
{...(controller
? { value: controller.textInput.value }
: { defaultValue })}
{...props}
{...controlledProps}
/>
);
};
@@ -1274,24 +1131,20 @@ export const PromptInputSubmit = ({
status,
children,
...props
}: PromptInputSubmitProps) => {
let Icon = <ArrowUpIcon className="size-4" />;
let ariaLabel = "发送消息";
if (status === "submitted") {
Icon = <Loader2Icon className="size-4 animate-spin" />;
ariaLabel = "正在发送";
} else if (status === "streaming") {
Icon = <SquareIcon className="size-4" />;
ariaLabel = "停止生成";
} else if (status === "error") {
Icon = <XIcon className="size-4" />;
ariaLabel = "重新发送";
}
return (
<InputGroupButton
aria-label={ariaLabel}
}: PromptInputSubmitProps) => {
let Icon = <ArrowUpIcon className="size-4" />;
if (status === "submitted") {
Icon = <Loader2Icon className="size-4 animate-spin" />;
} else if (status === "streaming") {
Icon = <SquareIcon className="size-4" />;
} else if (status === "error") {
Icon = <XIcon className="size-4" />;
}
return (
<InputGroupButton
aria-label="Submit"
className={cn(
"transition-all duration-300",
status === "streaming" &&
Loaded 100 of 1608 files, more files were not shown because too many files have changed in this diff. Show more