From 2bc90ece6bc9a6e17d249a7acbbcf5d7b92b488a Mon Sep 17 00:00:00 2001 From: yujiezhang-ops Date: Thu, 6 Aug 2026 10:59:34 +0800 Subject: [PATCH 1/2] docs: keep the CC Switch research notes out of the public repository The notes are a competitor teardown written for maintainers: they carry internal judgements ("do not move toward it", "the earlier note overstated this") and quote the other project's implementation scale. That reads differently once the repository is public, so the file stays on the maintainer's machine and leaves the tracked set. Its row in docs/internal/README.md goes with it, otherwise scripts/check-docs.py fails on the dangling relative link. --- .gitignore | 3 + docs/internal/README.md | 1 - docs/internal/cc-switch-reference-notes.md | 168 --------------------- 3 files changed, 3 insertions(+), 169 deletions(-) delete mode 100644 docs/internal/cc-switch-reference-notes.md diff --git a/.gitignore b/.gitignore index 5cd09fd6..7c5ee850 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,6 @@ site/ # 本机代码索引。是否建立索引由每个开发者自己决定,重建只需 `codegraph index .` .codegraph/ + +# 对竞品的定向调研笔记:含内部评价措辞,保留本机参考但不随开源仓库分发。 +docs/internal/cc-switch-reference-notes.md diff --git a/docs/internal/README.md b/docs/internal/README.md index a1643f41..c5c82df3 100644 --- a/docs/internal/README.md +++ b/docs/internal/README.md @@ -40,5 +40,4 @@ | [blank-machine-verification-plan.md](blank-machine-verification-plan.md) | 空白机器验证的断言清单(执行入口已移除) | | [recent-work-summary.md](recent-work-summary.md) | 一次阶段性完工清单,已被上面几份取代 | | [mvp-agent-installer-plan.md](mvp-agent-installer-plan.md) | 最初的 HTTP/Python 原型,仅存背景 | -| [cc-switch-reference-notes.md](cc-switch-reference-notes.md) | 对 CC Switch 的定向调研与采纳/不采纳结论 | | [release-evidence/](release-evidence/) | 历史发行包的 SHA-256 与 cleanroom 记录 | diff --git a/docs/internal/cc-switch-reference-notes.md b/docs/internal/cc-switch-reference-notes.md deleted file mode 100644 index d2741bb5..00000000 --- a/docs/internal/cc-switch-reference-notes.md +++ /dev/null @@ -1,168 +0,0 @@ -# CC Switch 参考笔记 - -对 [CC Switch](https://github.com/farion1231/cc-switch) 的一次定向调研,用途是为 OneAgent 的 Agent 配置界面找可借鉴的做法。**只做参考,不移植代码**——两者许可、技术栈与产品定位都不同。 - -调研版本:`cc-switch` 3.18.0(commit `708b387`,2026-07-27),MIT。克隆在 `output/reference/cc-switch`,该目录被 `.gitignore` 忽略,不进仓库。 - -## 1. 两者定位差异(先说清,避免误抄) - -| | CC Switch | OneAgent | -| --- | --- | --- | -| 形态 | Tauri 桌面应用(Rust + React) | Wails 桌面应用(Go + React) | -| 职责 | Provider 配置的**存取与切换** | Agent 的**检测、安装、配置** | -| 配置模型 | 整块存原始配置对象 | 结构化字段,由适配器翻译 | -| 外围能力 | 本地代理、熔断器、故障转移、用量统计、MCP、skills、prompts、sessions | 无 | -| 表单规模 | 共享编排器 `ProviderForm.tsx` 2693 行 + 共享 hooks/字段约 6000 行 + 各应用专属区块 | `AgentProfilePage.tsx` 263 行 | - -它的 `src/components/` 下有 19 个子目录(mcp、skills、prompts、sessions、proxy、usage…)。这些不在 OneAgent 的产品边界内(见 [产品边界基线](../product-boundary-baseline.md)),尤其**本地代理与故障转移属于明确禁止范围**,不予借鉴。 - -## 2. 配置模型:它存原始对象,我们存结构化字段 - -CC Switch 的 `Provider`(`src/types.ts:11`)核心只有一个配置字段: - -```ts -settingsConfig: Record // Claude 为 settings.json;Codex 为 { auth, config } -``` - -其余全是元数据:`icon` / `iconColor` / `category` / `sortIndex` / `notes` / `isPartner` / `inFailoverQueue`。 - -**含义**:存储层整块存 Agent 的原始配置对象。 - -**更正**:先前记录的「它不理解字段语义,用户需要自己懂 `settings.json` 的结构」过头了。存储层不解析语义,但 UI 与 Service 层仍会理解、校验和编辑字段——`ClaudeFormFields` 认得 API 格式、认证字段名与模型映射,`useCodexTomlValidation` 会校验 TOML。差异在存储模型,不在「是否理解语义」。 - -**更正**:先前记录的「CC Switch 从不安装 Agent」不准确。`src-tauri/src/commands/misc.rs:452` 起有一键安装,OpenClaw 走 `npm i -g openclaw@latest`,Hermes 走 `NousResearch/hermes-agent` 的官方 install.sh。这不改变 OneAgent 仍将两者列为 guide-only 的结论——理由是常驻网关形态被 ADR-002/ADR-003 划在范围外,与能否安装无关。 - -**OneAgent 的做法相反且更适合当前定位**:`agents/.json` 存 `provider` / `model` / `base_url` 等结构化字段,由 5 个适配器翻译成各 Agent 的格式。用户不需要知道目标文件长什么样。这个差异是设计选择,不是我们缺功能,**不要向它靠拢**。 - -字段量级对比:它的 Claude 表单认 12 个 `ANTHROPIC_*` 环境变量(含 Opus / Sonnet / Haiku / Fable 分模型指定),我们只写 4 个。 - -## 3. 值得借鉴:官方图标来源 - -CC Switch 依赖 **`@lobehub/icons-static-svg`**(MIT,723 个 AI 品牌 SVG)。核对结果: - -| 我们需要的 | lobehub 是否提供 | -| --- | --- | -| Codex(openai) | **有** `openai.svg` | -| Claude Code(claude / anthropic) | 有 | -| Cursor(guide-only) | 有 | -| OpenCode | 无 | -| Aider | 无 | -| Kilo CLI | 无 | - -`openai.svg` 的形态与 OneAgent 的图标规范完全一致,可直接内联: - -``` - -``` - -这把官方图标覆盖从 2/5 提到 3/5,Codex 不必再自绘。OpenCode 沿用 simple-icons(CC0)已有的官方图标,只有 Aider 与 Kilo 仍需自绘。 - -### 更正:八个 Agent 全部有官方图标 - -先前判断「Codex / Aider / Kilo 无官方图标」是错的,那只说明 simple-icons 里没有。逐个核对各项目自己的站点与仓库后,八个全都有: - -| Agent | 官方来源 | -| --- | --- | -| Codex | lobehub `openai.svg`(MIT) | -| Claude Code | `claude.ai/favicon.svg`(品牌橙 `#D97757`) | -| Cursor | `cursor.com/favicon.svg` | -| OpenCode | lobehub `opencode.svg`(MIT) | -| OpenClaw | 官方仓库 `docs/assets/pixel-lobster.svg`(MIT) | -| Hermes | `hermes-agent.nousresearch.com/icon.png`(48px,无矢量版) | -| Kilo CLI | `kilocode.ai/favicon/favicon.svg` | -| Aider | `aider.chat/assets/icons/favicon-32x32.png` | - -这些来源只能证明「站点上存在一个图像」,不能单独证明 OneAgent 有权复制并随二进制再分发。当前实现只保留有完整权利清单的 Codex、OpenCode、OpenClaw 资产;Claude Code、Cursor、Hermes、Kilo CLI 和 Aider 使用通用 Lucide 符号。**结论:判断某个品牌「没有官方图标」之前,要查该项目自己的站点;决定能否随产品再分发之前,还要取得许可证或书面授权。** - -两个资产不能直接用,需换等价版本:`openai.com/favicon.svg` 与 `opencode.ai/favicon.svg` 都带 `:root` CSS 变量和 `prefers-color-scheme` 媒体查询,内联进宿主文档会污染全局样式;`aider.chat/assets/logo.svg` 是 200×60 的文字标加高斯模糊滤镜,不是方形图标。 - -**OpenClaw 的标志是龙虾,不是螃蟹。** 所以图标要以上游官方资产为准,不要以任何第三方项目的转绘为准——这一条对我们自己同样适用。 - -### OpenClaw 与 Hermes 的图标不可取用 - -核对 `src/icons/extracted/`(98 个文件)的结果: - -- **OpenClaw** 是 CC Switch **自绘**的彩色 SVG,`viewBox="0 0 120 120"`,用 `linearGradient` 从 `#ff4d4d` 渐变到 `#991b1b`,配青色眼睛。不是官方 logo。 -- **Hermes** 是一张 256×256 PNG(39 KB),不是矢量。 - -两者都无法满足 24×24 单色 `currentColor` 的规范:渐变填充无法继承 `currentColor`,位图在 18px 渲染位与矢量字形并排时轻重不一。因此这两个按同一几何规范自绘,而不是取用 CC Switch 的资产。这不是许可问题(MIT 允许取用),是形态不兼容。 - -**注意**:这个包在 CC Switch 的源码里没有被引用,实际使用的是 `src/assets/icons/` 下手工的 `chatgpt.svg` 与 `claude.svg`。结论对我们有用的部分是方法论:「某个项目装了什么依赖」不能作为该依赖可用的证据,仍需自己核对。 - -**许可与商标**:MIT 覆盖 SVG 文件本身,不覆盖商标权。在自己 UI 内标示「这一行是哪个 Agent」属指示性使用;不得用作 OneAgent 的产品视觉资产。统一 `currentColor` 单色渲染,既统一风格也避免为第三方商标着色。 - -## 4. 值得借鉴:高级项用折叠,不做模式切换 - -`ClaudeFormFields.tsx:800` 的做法: - -```tsx - - - {!advancedExpanded &&

{t("providerForm.advancedOptionsHint")}

} - - -``` - -两个细节值得抄: - -**折叠而非模式切换。** 默认收起、需要时展开,比切换「简单/高级」模式轻,也不会让用户困在错误的模式里出不来。 - -**收起时显示一行说明里面有什么**,而不是只留一个光秃的三角。它的原文是: - -> 包含 API 格式、认证字段、模型映射等配置。大多数场景下保持默认即可。 - -最后一句尤其值得学:明确告诉用户「不用管」,而不是让人担心自己漏配了什么。 - -它折叠区里的字段:API 格式(Anthropic / OpenAI Chat / OpenAI Responses)、认证字段名(`ANTHROPIC_AUTH_TOKEN` vs `ANTHROPIC_API_KEY`)、模型映射与显示名、分模型指定、一键设置。 - -### OneAgent 未来的候选高级项 - -按同一收纳方式,优先级从高到低: - -1. **认证字段名切换**——已有真实差异(Claude 系可读两个不同变量名)。 -2. **分模型指定**——Opus / Sonnet / Haiku 各自的模型名,Claude Code 支持。 -3. 请求超时。 -4. 自定义 User-Agent。 - -现阶段都不做。当前 218 行的详情页方向正确,加高级项前应先有真实需求。 - -## 5. 值得借鉴:预设机制(方向与我们相反) - -它为每个 Agent 备了 `src/config/*ProviderPresets.ts`(Claude、Codex、Gemini、OpenCode 各一份),用户选预设而非从零填写。预设的最小形态: - -```ts -{ - name: "Claude Official", - websiteUrl: "https://www.anthropic.com/claude-code", - settingsConfig: { env: {} }, - isOfficial: true, - category: "official", - icon: "anthropic", -} -``` - -**与 OneAgent 的 `profiles/` 模板方向相反**:它的预设是**内置的服务商清单**(我们出,用户选),我们的模板是**用户自存的组合**(用户出,用户复用)。两者不冲突,可以并存——内置预设降低首次配置成本,用户模板降低重复配置成本。 - -若将来要做内置预设,注意 `isPartner` / `primePartner` / `partnerPromotionKey` 这类商业合作字段**不要引入**:[产品边界基线](../product-boundary-baseline.md) 第 8 节要求公开权益文案不得承诺固定额度,带推广属性的预设排序会踩这条线。 - -## 6. UI 布局:与我们已高度一致 - -`ProviderCard.tsx` 的结构是**图标 + 主信息 + 右侧操作 + 底部分隔线**,与 OneAgent 刚落地的 `AgentManageRow` 基本同构,无需调整。 - -它多出的部件是我们当前不需要的:健康状态指示器(`HealthStatusIndicator`)、故障转移优先级徽章(`FailoverPriorityBadge`)、拖拽排序(`@dnd-kit`)。前两个依赖本地代理,属于边界外。 - -## 7. 结论 - -**采纳**: - -- lobehub 的 `openai.svg` 替换自绘的 Codex 图标(第 3 节)。 -- 高级项一律用折叠收纳,收起时带一行说明(第 4 节)。 - -**明确不采纳**: - -- 整块存原始配置 —— 我们的结构化模型更适合「用户不必懂目标格式」的定位。 -- 本地代理、熔断器、故障转移 —— 产品边界禁止。 -- 商业合作伙伴字段与推广排序 —— 与公开权益文案约束冲突。 -- 拖拽排序、健康徽章 —— 当前无对应需求。 - -相关文档:[前端管理控制台改造计划](frontend-management-console-plan.md)、[产品边界基线](../product-boundary-baseline.md)、[CC Switch 可选配置说明](../ai-agent-kit/zh/tools/cc-switch.md)。 From 029483f16eee509e4d5e769581975e46ef1071df Mon Sep 17 00:00:00 2001 From: yujiezhang-ops Date: Thu, 6 Aug 2026 11:00:11 +0800 Subject: [PATCH 2/2] docs: add a sponsors section with the PPIO and Novita logos Both sponsors are also built-in Providers, so providers.lock.json now says so: relationship moves from "none" to "sponsor" and each disclosure field carries the text. public-site-operations.md names those fields as the source of truth for commercial disclosure, and a README that acknowledges a sponsor while the lock file declares no relationship would be two contradictory public statements about the same fact. Both READMEs repeat the boundary the policy already requires: sponsorship does not affect Agent rank, compatibility conclusions, default selection, or connection tests, and the built-in order lives in the lock file regardless. The NOTICE trademark section had to split. It claimed every mark in the project implies no "endorsement, affiliation or sponsorship", which a sponsor logo contradicts by definition. Agent marks stay nominative use; sponsor marks are a separate, permission-based case that keeps its brand colours. They ship in the two READMEs only and reach no release binary, since manifest_embed.go embeds the lock files and frontend/dist but never docs/. --- NOTICE | 21 ++++++++++++++++----- README.md | 17 +++++++++++++++++ README_ZH.md | 15 +++++++++++++++ docs/assets/sponsors/asset-rights.json | 21 +++++++++++++++++++++ docs/assets/sponsors/novita-color.png | Bin 0 -> 1931 bytes docs/assets/sponsors/ppio-color.png | Bin 0 -> 7382 bytes providers.lock.json | 8 ++++---- 7 files changed, 73 insertions(+), 9 deletions(-) create mode 100644 docs/assets/sponsors/asset-rights.json create mode 100644 docs/assets/sponsors/novita-color.png create mode 100644 docs/assets/sponsors/ppio-color.png diff --git a/NOTICE b/NOTICE index 929aa75b..393af171 100644 --- a/NOTICE +++ b/NOTICE @@ -49,8 +49,19 @@ redistribute it. The four retained image assets, for Codex, Claude Code, OpenCode, and Kilo CLI, are listed with source, license, owner, and SHA-256 in frontend/src/components/icons/asset-rights.json. -This is nominative use: the labels identify the referenced products and do not -imply endorsement, affiliation or sponsorship. The image assets keep their -published geometry and are not re-drawn. Each is distributed as a single-colour -glyph painted with fill="currentColor", so it takes the surrounding text colour -by design rather than carrying a brand colour that is being altered. +The Agent marks described above are nominative use: the labels identify the +referenced products and do not imply endorsement, affiliation or sponsorship. +The image assets keep their published geometry and are not re-drawn. Each is +distributed as a single-colour glyph painted with fill="currentColor", so it +takes the surrounding text colour by design rather than carrying a brand colour +that is being altered. + +Sponsor marks are a separate case and are not nominative use. The PPIO and +Novita logos under docs/assets/sponsors/ are reproduced with each owner's +permission to identify a sponsor of this project, and they do carry their brand +colours as published. They appear only in README.md and README_ZH.md, never in +the application interface, and are listed with source, owner, and SHA-256 in +docs/assets/sponsors/asset-rights.json. Each logo remains the property of its +owner. Sponsorship does not affect Agent rank, compatibility conclusions, +default selection, or connection tests; the commercial relationship for each +Provider is declared in providers.lock.json. diff --git a/README.md b/README.md index c59a60d0..133e87c7 100644 --- a/README.md +++ b/README.md @@ -208,6 +208,23 @@ maintainer-facing and stays in Chinese. past work. Commands in there may have stopped working as tools were removed; that directory's README names the current entry points. +## Sponsors + +OneAgent's development is supported by: + +

+ PPIO +    + Novita +

+ +Both are also built-in Providers in OneAgent. Sponsorship does not change which +Provider is recommended or how one is verified: every Provider is probed against +the protocol its Agent actually speaks, and the built-in list is ordered in +`providers.lock.json` independently of any commercial relationship. See +[providers.lock.json](providers.lock.json) for each entry's declared +relationship and disclosure. + ## Licence Apache License 2.0. See [LICENSE](LICENSE). diff --git a/README_ZH.md b/README_ZH.md index 13244fa8..ad0ebef0 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -154,6 +154,21 @@ Wails 仍处于 Alpha,当前不发布 Stable,不做平台签名、公证或 - [internal/](docs/internal/README.md):各次改造的完工记录与验证清单。里面的命令可能已随工具移除而失效,该目录的 README 说明了当前的替代入口。 +## 赞助 + +OneAgent 的开发由以下机构支持: + +

+ PPIO +    + Novita +

+ +两者同时也是 OneAgent 的内置 Provider。赞助关系不改变推荐哪个 Provider、也不改变 +如何验证它:每个 Provider 都按其 Agent 实际使用的协议探测,内置列表的顺序在 +`providers.lock.json` 里独立定义,与商业关系无关。各条目声明的关系与披露见 +[providers.lock.json](providers.lock.json)。 + ## 许可证 Apache License 2.0,见 [LICENSE](LICENSE)。 diff --git a/docs/assets/sponsors/asset-rights.json b/docs/assets/sponsors/asset-rights.json new file mode 100644 index 00000000..028c3b62 --- /dev/null +++ b/docs/assets/sponsors/asset-rights.json @@ -0,0 +1,21 @@ +{ + "note": "Sponsor logos reproduced with the owner's permission to identify a sponsor of this project. Unlike the Agent marks in frontend/src/components/icons/asset-rights.json, these are not nominative use and they keep their published brand colours. They appear only in README.md and README_ZH.md, never in the application interface, and are not compiled into any release binary.", + "assets": { + "ppio": { + "file": "ppio-color.png", + "owner": "PPIO", + "home": "https://ppio.com/", + "basis": "permission-from-owner", + "usage": "readme-only", + "sha256": "de34cd65b95756a7438feef7731e3f661cb16ed896750e2db74c4adb17bfa875" + }, + "novita": { + "file": "novita-color.png", + "owner": "Novita", + "home": "https://novita.ai/", + "basis": "permission-from-owner", + "usage": "readme-only", + "sha256": "6546afdf0ae4a374e13e884fdb2f34264db81303dd50640f1fe902686dc10f5f" + } + } +} diff --git a/docs/assets/sponsors/novita-color.png b/docs/assets/sponsors/novita-color.png new file mode 100644 index 0000000000000000000000000000000000000000..bb23a95183ff3d6a4cb8abaff0794f770b99e66e GIT binary patch literal 1931 zcmeAS@N?(olHy`uVBq!ia0y~yU}^wi4rZW;wXmfikP-^;332twEL6H$Bm1xbNJ^fm zSH4>F%A{{4P?ohM$S;^-2S+_u%$dE>KmpDIkH}&M25w;xW@MN(M}mQYozK(7F{I+w z+gsg*cML>W4q9KFUVm!Z|4B>_4s5kmoDi$PxaYX@Bo$A3pnvz*nV)x1J)qvG#kh|n zglmGsRtC-x?onz81pz}mOO}K}BZJV2)CLwNj|I~hg*X%%qu4wY8d$O>5H2=JK zHX6Q^zsvb zU>GRWD}8XNzdqTa_4WO)3IPwlf3Ff)@!|h_S%t<|-{kFqVV?8-2G05cGh=4t%V+}IpA2I&J-hBVf)=mctN-# hU1}Qa_1WD^<%h3Drh2t3?*>+v44$rjF6*2Ung9pg&ustz literal 0 HcmV?d00001 diff --git a/docs/assets/sponsors/ppio-color.png b/docs/assets/sponsors/ppio-color.png new file mode 100644 index 0000000000000000000000000000000000000000..71b8554153beefb8f27e76bc4de0fe98beb9c325 GIT binary patch literal 7382 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