Pull Request已成功合入, 合并人@openJiuwen-bot
(感谢 wang_cheng_zhao 的贡献)变更摘要
本 PR 修复首次打开 ScienceDiscovery 时本地认证失败被重复提示的问题:此前未配置本地访问令牌会同时在右上角 Toast、设置警示条和 Connection 正文三处显示 Unauthorized。改动后本地 401 只由 Connection 一处呈现引导(空令牌为中性说明、错误令牌为拒绝提示),会话中令牌失效时后台轮询(内存图、产物下载、任务面板等)不再叠加红字,500 与网络故障仍走原有错误提示。为此在 api/auth.js 引入携带 HTTP 状态码的 ApiRequestError 与 isAuthFailure 判定,各组件错误回调由 string 改为透传 string | Error;同时区分两种凭据文案(settings.localToken 改为「本地服务访问令牌 / Local service access token」、settings.apiToken 改为「外部模型 API Key / External model API Key」),并在启动日志打印 Open to sign in: http://<host>:<port>/#[REDACTED] 登录链接,由新增的 loadLocalAccessToken在 React 挂载前将 token 片段写入localStorage` 并从地址栏移除。
主要改动
- 单一认证引导与错误路由:
App.tsx中setError、reportSystemSettingsError、reportScopedSettingsError对isAuthFailure直接返回(401 不再弹 Toast/警示条),promptForToken改为setTokenRejected(Boolean(token))按令牌是否存在区分空令牌中性说明与拒绝提示,AgentActivityPanel等轮询组件在 401 时也不再叠加错误。 - 类型化认证错误
ApiRequestError:artifacts.ts、runs.ts、evolve.ts、plugins.ts、client.ts等在!response.ok时改抛携带 status 的ApiRequestError并调用reportAuthStatus,使认证失败按 HTTP 状态码而非 "Unauthorized" 文本识别;EnvironmentManager、MemoryGraphView、RemoteCompute、SkillManager等组件的onError签名由(message: string)改为(reason: string | Error)以透传类型。 - 启动登录链接与令牌落盘:新增
local-access-token.ts的loadLocalAccessToken,在挂载前解析#[REDACTED] 片段、写入TOKEN_STORAGE_KEY并用history.replaceState移除片段(空片段不覆盖已存令牌);main.tsx将initialToken传入App;services/api与services/launcher的accessTokenBanner改为打印Open to sign inURL,并对0.0.0.0/::绑定地址映射为127.0.0.1`。 - 凭据文案区分与令牌保存校验:i18n
messages.ts将本地令牌与模型 Key 文案改名,新增settings.tokenHelp、settings.tokenStorageHelp说明「Open to sign in」链接与保存方式;App.tsx保存前先用new ApiClient(candidate).listProjects()校验令牌,认证失败则不落盘、留在 Connection 拒绝提示。 - 测试覆盖:新增 E2E
test/journey-local-token-onboarding.spec.ts(中/英双语:空令牌单处引导、错误令牌恢复、启动链接自动登录并刷新保持、会话内令牌失效仅一处 Connection)以及单测ApiAuthErrorPropagation.test.tsx、LocalAccessToken.test.tsx,并更新AuthTokenPrompt.test.tsx、ErrorFeedbackRouting.test.tsx等验证 401 不按文本过滤、500 与网络错误仍正常提示。


代码审查
审查结论
发现汇总
共报告 4 项问题:
| 优先级 | 数量 | 概要 |
|---|---|---|
| P0 | 0 | — |
| P1 | 0 | — |
| P2 | 1 | operator 令牌在启动日志明文回显(安全回退) |
| P3 | 3 | 存储失败导致模块级白屏;关闭弹窗后认证全静默无再提示;令牌落盘异常被空 catch 吞掉 |
总体风险评估
中低风险,建议合入前处理 P2 项。 本 PR 的核心目标(三重 Unauthorized 收敛为 Connection 单点引导、凭据文案区分、启动登录链接)实现方式整体正确:isAuthFailure 基于 ApiRequestError.status === 401 精确判定(不按文本嗅探),所有 onError 回调类型统一为 string | Error 并在 App 层过滤认证错误,#token= 片段在挂载前消费、不随 HTTP 请求发送,配套单测/组件测/E2E 覆盖充分。主要问题集中在两处:一是把「operator 显式令牌永不回显」的既有安全契约整体移除(P2,虽为功能所需但属真实安全降级,建议对 environment 来源恢复不回显明文行的旧行为);二是几处边缘可靠性问题(存储不可用时的白屏/静默失败、弹窗被关闭后无声失效),均为窄触发、低概率。
逐文件审查清单
- apps/web/src/AgentActivityPanel.tsx — 401 轮询/操作静默,符合设计;无问题
- apps/web/src/App.tsx — 发现 3 项(见 F3/F4 及 token 流整体核对;其余 hunk 为 onError 类型透传,调用方均兼容)
- apps/web/src/ArtifactLifecycleControls.tsx — onError 类型透传;无问题
- apps/web/src/EnvironmentManager.tsx — onError 类型透传;无问题
- apps/web/src/EvidenceModal.tsx — onError 处理 Error→message;无问题
- apps/web/src/IdeaResearchCard.tsx — onError 类型透传;无问题
- apps/web/src/IdeaTreeView.tsx — onError 类型透传;无问题
- apps/web/src/MemoryGraphExplorer.tsx — onError 类型透传;无问题
- apps/web/src/MemoryGraphView.tsx — onError 类型透传;无问题
- apps/web/src/Orchestration.tsx — onError 类型透传;无问题
- apps/web/src/ProviderModelSettings.tsx — providerOperationError 透传认证错误;无问题
- apps/web/src/RemoteCompute.tsx — 凭据保存后刷新失败按认证错误透传;无问题
- apps/web/src/RunnerEnvironmentSettings.tsx — onError 类型透传;无问题
- apps/web/src/RuntimeControls.tsx — onError 类型透传;无问题
- apps/web/src/ScientificArtifacts.tsx — onError 类型透传;无问题
- apps/web/src/SkillManager.tsx — onError 透传 Error、localError 保留本地文案;无问题
- apps/web/src/SkillWorkspaceDialog.tsx — onError 类型透传;无问题
- apps/web/src/api/artifacts.ts — 原始 fetch 路径补 reportAuthStatus+ApiRequestError;无问题
- apps/web/src/api/client.ts — trajectory 导出补 ApiRequestError;无问题
- apps/web/src/api/evolve.ts — 流式端点补 reportAuthStatus;无问题
- apps/web/src/api/plugins.ts — 订阅端点补 ApiRequestError;无问题
- apps/web/src/api/runs.ts — 三处流式/导出补 ApiRequestError;无问题
- apps/web/src/evolve/EvolvePanel.tsx — onError 类型透传;无问题
- apps/web/src/i18n/messages.ts — 文案键增删一致,无悬空引用;无问题
- apps/web/src/local-access-token.ts — 片段消费逻辑与测试一致;异常传播问题见 F2
- apps/web/src/main.tsx — 发现 F2(模块级存储异常白屏)
- apps/web/src/settings-error-routing.ts — 透传 Error 保留 status;无问题
- apps/web/tests/AgentActivityPanel.test.tsx — 覆盖 401/500 路由;无问题
- apps/web/tests/ApiAuthErrorPropagation.test.tsx — 覆盖 13 个端点 status 保留;无问题
- apps/web/tests/AppSettingsDefaults.test.tsx — 适配新签名;无问题
- apps/web/tests/AuthTokenPrompt.test.tsx — 覆盖 gate/静默规则;无问题
- apps/web/tests/ErrorFeedbackRouting.test.tsx — 覆盖设置路由透传;无问题
- apps/web/tests/LocalAccessToken.test.tsx — 覆盖片段消费;其断言的抛出行为即 F2 根因
- apps/web/tests/ProviderModelPrice.test.tsx — 覆盖 providerOperationError;无问题
- apps/web/tests/RemoteCompute.test.tsx — 适配 Error 断言;无问题
- services/api/src/http/bootstrap-tokens.test.ts — 覆盖 URL 编码与地址格式;无问题
- services/api/src/http/bootstrap-tokens.ts — 发现 F1(operator 令牌明文回显)
- services/api/src/http/index.ts — 使用实际绑定端口;无问题
- services/launcher/src/bootstrap-tokens.test.ts — 覆盖三种来源 URL;无问题
- services/launcher/src/bootstrap-tokens.ts — F1 的重复实现
- services/launcher/src/serve.ts — IPv6/0.0.0.0 地址格式化正确;无问题
- test/e2e-auth.ts — 提示文案同步更新;无问题
- test/journey-local-token-onboarding.spec.ts — 双语旅程覆盖完整;无问题
| 类型 | 数量 |
|---|---|
| 🔴 阻塞 | 0 |
| 🟡 建议 | 1 |
💬 仅评论


欢迎来到 openJiuwen 社区
Hey @wang_cheng_zhao , 感谢你对社区的贡献.
机器人使用手册
有关指令的使用,可以点击 此处 查看详情。开发人员可以在每个PR或Issue下方评论特定指令来触发机器人任务。


The pipeline(pipeline number:130) is running. Please wait a moment...


AI 自动检视,仅供参考,问题都需要人工评估分析
本 PR 针对 #88:首次打开时多重 Unauthorized 提示,以及本地令牌上手体验。相对最新 origin/main 共 9 个提交(behind=0),覆盖启动登录链接、Connection 单一引导、凭据命名区分,以及 401 错误路由收敛。
整体做法合理:浏览器在 React 挂载前用 loadLocalAccessToken 消费 #token= 并写入 localStorage、再从地址栏剥离,令牌仍只走 Bearer,fragment 不进 HTTP;isAuthFailure 严格依赖 ApiRequestError.status === 401,Toast / 设置警示条 / Activity 面板不再叠 Unauthorized;空令牌与错误令牌都落在 Connection,保存前先用 candidate 校验再持久化。启动 banner 区分「本地服务访问令牌」与「外部模型 API Key」,并提示保管 sign-in URL。UT(含 stream/blob 状态保留、后台轮询路由)与双语 E2E journey 覆盖面与改动规模匹配。
文档与本次行为不同步。根 README / README_zh 已改为打开 Open to sign in,但 README 指向的快速开始与部署指南仍写「打开 http://127.0.0.1:4310,用启动打印的 token 登录」——docs/en/tutorial/01-quick-start.md、docs/zh/tutorial/01-quick-start.md,以及 docs/en/how-to/deployment.md / docs/zh/how-to/deployment.md 多处仍是旧流程;docs/en/how-to/configure-custom-mcp.md 仍称 “local API token”。合入前建议把这些入口文档改成与 Connection / 启动链接一致,并同步模型侧「外部模型 API Key」命名,避免用户按教程走回旧路径。
另请确认:此前 SCIENCE_AGENT_AUTH_TOKEN 环境令牌刻意不在控制台回显(避免共享终端 / CI 日志留存),现会随 Open to sign in URL 与明文 token 一并打印。若接受该取舍可保留,否则应对 environment 来源继续只提示变量名、不打印值。
条件合


✅ 流水线 77711aabe4e84c62bd8269109af54658 执行成功。
可在 https://gitcode.com/openJiuwen/sciencediscovery/pull/130/check 查看完整构建日志。
在 PR 评论中发送 rerun 可重新触发 CI 流水线。
| 任务名称 | 子任务 | 状态 | 详情 |
|---|---|---|---|
| 代码检查 | SCA(开源合规) | PASSED | 点此跳转 |
| Anti-poison(防投毒) | PASSED | 点此跳转 | |
| CodeCheck(静态检查) | PASSED | 点此跳转 | |
| Blacklist(禁用词) | PASSED | 点此跳转 | |
| UT | host tier | PASSED | 公开日志 |
| guest tier (QEMU TCG sandbox) | PASSED | 公开日志 | |
| ST | - | PASSED | 公开日志 |
| Binary | x86_64 debug package | PASSED | binary · SHA256SUMS |
| aarch64 debug package | PASSED | binary · SHA256SUMS |


🟡 Medium Priority
Changed line → affected behavior/contract → failure mode → suggested fix.
变更行:services/api/src/http/bootstrap-tokens.ts 第 111-117 行(以及 services/launcher/src/bootstrap-tokens.ts 第 109-115 行)中,accessTokenBanner 无条件输出两条含令牌文本的行:Open to sign in: http://<host>:<port>/#[REDACTED] 和 Local service access token (SCIENCE_AGENT_AUTH_TOKEN):
行为/契约:旧实现(本 diff 删除的分支)对 authTokenSource === "environment" 的 operator 显式配置令牌刻意只命名、不回显——注释原文为 "they already have it, and console output can outlive the process in shared terminals and CI logs"。本 PR 为提供「启动登录链接」功能,把该保护整体移除,operator 令牌现在总是以明文打印(既在 URL 片段中,也在单独一行中),测试甚至显式断言 explicit.includes("#[REDACTED] === true。
失败模式:CI 日志、共享终端、进程崩溃转储等会永久保留启动输出;任何能读到该日志的人即可用该 bearer 令牌访问本地服务(尤其当服务绑定到非回环地址时,见 index.ts 中对 0.0.0.0/:: 的告警分支)。这是对既有安全契约的有意回退,但属于真实的安全降级,且 banner 自身也以 "Keep the sign-in URL private" 承认其敏感性。
(launcher 侧 services/launcher/src/bootstrap-tokens.ts 为同一根因的重复实现,一并修复。)
建议:对 authTokenSource === "environment" 的情况恢复「不回显独立明文令牌行」的旧行为:仅打印登录 URL(功能必需),去掉单独打印的 Local service access token (...): <token> 明文行,或将其替换为「令牌来自 SCIENCE_AGENT_AUTH_TOKEN,可在环境变量中查看」的提示。


感谢检视与反馈。已按评审意见完成以下调整与确认:
-
文档同步已完成(提交
451584b5):- 已同步对齐
docs/{zh,en}/tutorial/01-quick-start.md、docs/{zh,en}/how-to/deployment.md、docs/{zh,en}/how-to/configure-custom-mcp.md、docs/{zh,en}/reference/等共 17 篇文档。 - 所有入门、部署与配置引导均已统一为通过启动日志中的
Open to sign in链接自动完成本地认证与持久化保存;全面规范并区分「本地服务访问令牌(Local service access token)」与「外部模型 API Key(External model API Key)」,避免用户误填。
- 已同步对齐
-
关于环境变量令牌明文打印与登录链接的取舍:
- 经人工评估与产品决策,确认接受控制台日志输出
Open to sign in链接与本地服务访问令牌明文(包含SCIENCE_AGENT_AUTH_TOKEN来源)。这是为了保障本地与容器首次部署的操作可观察性与极简接入体验;同时横幅已明确输出「This is not an external model API Key. Keep the sign-in URL private」安全提示。因此保持当前 banner 输出设计,不针对环境变量来源隐藏明文。
- 经人工评估与产品决策,确认接受控制台日志输出
-
测试验证:
- 更新至提交
451584b5后已重新完成全量静态检查、单测与 E2E 验证:pnpm build: PASSpnpm --filter @sciencediscovery/web typecheck: PASSpnpm --filter @sciencediscovery/web test: PASS(780/780)- launcher 与 API bootstrap / serve 单测: PASS(39/39)
git diff --check: PASS- Playwright E2E
journey-local-token-onboarding.spec.ts: PASS(6/6,0 skipped,耗时约 49.0s)
- PR 正文已同步更新被测提交 SHA 与最新验证结论。
- 更新至提交


The pipeline(pipeline number:130) is running. Please wait a moment...


AI 自动检视,仅供参考,问题都需要人工评估分析.
本轮相对上一轮(e5a74eb → 451584b)仅新增文档对齐提交:把 quick-start / deployment / configure-custom-mcp 及若干 reference、explanation(中英文)统一到「Open to sign in」链接 + 本地服务访问令牌的叙事,并与 README 已有表述一致。代码与测试无相对上一轮无变。
上一轮未决项复核:
- 文档不同步——已修复。原先仍教直接打开 http://127.0.0.1:4310 再粘贴打印 token、以及「local API token」等旧说法的 quick-start、deployment、configure-custom-mcp 等已改为优先打开启动日志中的登录链接;直接打开 4310 仅作为可粘贴令牌的备选路径保留,表述合理。
- 启动日志明文回显 SCIENCE_AGENT_AUTH_TOKEN / 来源——本轮无代码改动,行为与上一轮相同;文档现已同步描述「打印登录链接与本地服务访问令牌」,可视为有意设计(本地 loopback 场景),不再作为合入阻塞。
说明:相对最新 origin/main 仍 behind 约 12 个提交,合入前建议 rebase/merge 一下主线,与本次变更无关。
可合


✅ 流水线 ecfee21212f6430db9e92d6d0a3f0234 执行成功。
可在 https://gitcode.com/openJiuwen/sciencediscovery/pull/130/check 查看完整构建日志。
在 PR 评论中发送 rerun 可重新触发 CI 流水线。
| 任务名称 | 子任务 | 状态 | 详情 |
|---|---|---|---|
| 代码检查 | SCA(开源合规) | PASSED | 点此跳转 |
| Anti-poison(防投毒) | PASSED | 点此跳转 | |
| CodeCheck(静态检查) | PASSED | 点此跳转 | |
| Blacklist(禁用词) | PASSED | 点此跳转 | |
| UT | host tier | PASSED | 公开日志 |
| guest tier (QEMU TCG sandbox) | PASSED | 公开日志 | |
| ST | - | PASSED | 公开日志 |
| Binary | x86_64 debug package | PASSED | binary · SHA256SUMS |
| aarch64 debug package | PASSED | binary · SHA256SUMS |


main,281e2322-feat(auth): print local service sign-in URLs at startup,5be79349-fix(web): streamline local access token onboarding,0f16fa70-test(auth): cover bilingual onboarding and invalid link recovery,0414b532-docs(auth): explain automatic local sign-in links,4db0d6e8-test(auth): keep model credential labels visible in evidence,d98ea271-fix(web): preserve authentication errors through feedback routing,1ce070ae-fix(api): retain HTTP status for streamed and binary responses,be2c85bc-test(auth): cover expired tokens in existing sessions,e4aa6ad8-fix(auth): avoid duplicate activity panel authentication alerts,5a19874c-docs: align quick-start, deployment, and MCP guides with token sign-in URLmain,281e2322-feat(auth): print local service sign-in URLs at startup,5be79349-fix(web): streamline local access token onboarding,0f16fa70-test(auth): cover bilingual onboarding and invalid link recovery,0414b532-docs(auth): explain automatic local sign-in links,4db0d6e8-test(auth): keep model credential labels visible in evidence,d98ea271-fix(web): preserve authentication errors through feedback routing,1ce070ae-fix(api): retain HTTP status for streamed and binary responses,be2c85bc-test(auth): cover expired tokens in existing sessions,e4aa6ad8-fix(auth): avoid duplicate activity panel authentication alerts,5a19874c-docs: align quick-start, deployment, and MCP guides with token sign-in URL已完成基于主线最新提交(2106e9ec)的 rebase,冲突已解决:
- 冲突处理:
- 解决
apps/web/src/IdeaResearchCard.tsx中与主线 i18n 改造的冲突,合并保留了useLocale的t引用,同时保留了本 PR 对onError: (reason: string | Error) => void错误对象的透传,确保 401 鉴权失效路由与多语言支持兼备。
- 解决
- 测试验证(针对新 HEAD
5a19874c):pnpm build: PASSpnpm --filter @sciencediscovery/web typecheck: PASSpnpm --filter @sciencediscovery/web test: PASS(781/781)- launcher / API bootstrap 与 serve 单测: PASS(39/39)
git diff --check origin/main..HEAD: PASS- Playwright E2E
journey-local-token-onboarding.spec.ts: PASS(6/6,0 skipped,约 49.2s)
- PR 状态:
- 已同步推送到
gitcode-fork,GitCode 冲突已消除(conflict_passed: true,mergeable: true)。PR 正文测试结论与基线 SHA 已同步更新。
- 已同步推送到


The pipeline(pipeline number:130) is running. Please wait a moment...


AI 自动检视,仅供参考,问题都需要人工评估分析.
相对上一轮 HEAD 451584b5,本轮源分支强制更新到 5a19874c:实质是 rebase 到最新 origin/main(2106e9ec,behind 从 12 降到 0),把中间已合入的 Idea Tree 读者语言渲染与 /evolve 文档等一并带上。相对 origin/main...HEAD 仍是原先那 10 个提交(SHA 重写);顶提交「docs: align quick-start…」与上一轮 patch-id 一致,文档侧 Open to sign in / 本地服务访问令牌表述仍对齐,未再引入新的功能改动。
与 main 上 Idea Tree 相关文件的交叠(如 App.tsx / IdeaResearchCard / IdeaTreeView 的 onError 签名、messages.ts 连接文案)看起来是干净重放:鉴权失败继续走 Connection 引导而非重复 toast,思路与上一轮一致。
结论:可合


/merge


🔄 收到 @wang_cheng_zhao 的 /merge,正在校验并把 PR !130 以 rebase 方式合入 main…


✅ 自动合并完成(由 @wang_cheng_zhao 的 /merge 评论触发)。
PR !130 已以 rebase 方式合并到 main:2106e9e..5a19874(10 个提交)
GitCode 的审批规则尚未满足(审批人:hong-ye-zhou,yi-zhang95),已按 CODEOWNERS 授权强制合入。


✅ 流水线 71e39cb391ae43c784b26eb42729b06b 执行成功。
可在 https://gitcode.com/openJiuwen/sciencediscovery/pull/130/check 查看完整构建日志。
在 PR 评论中发送 rerun 可重新触发 CI 流水线。
| 任务名称 | 子任务 | 状态 | 详情 |
|---|---|---|---|
| 代码检查 | SCA(开源合规) | PASSED | 点此跳转 |
| Anti-poison(防投毒) | PASSED | 点此跳转 | |
| CodeCheck(静态检查) | PASSED | 点此跳转 | |
| Blacklist(禁用词) | PASSED | 点此跳转 | |
| UT | host tier | PASSED | 公开日志 |
| guest tier (QEMU TCG sandbox) | PASSED | 公开日志 | |
| ST | - | PASSED | 公开日志 |
| Binary | x86_64 debug package | PASSED | binary · SHA256SUMS |
| aarch64 debug package | PASSED | binary · SHA256SUMS |


What type of PR is this?
/kind bug
What does this PR do / why do we need it:
首次用浏览器打开本机 ScienceDiscovery 时,未配置本地访问令牌会被当成三次独立失败:右上角 Toast、设置警示条、Connection 正文红框同时显示
Unauthorized。输入框还叫Local API token,容易把外部模型 API Key 粘进去。启动日志只打印裸 token,用户必须手工复制粘贴。本 PR 按 #88 已确认方案修复:
Open to sign in: http://<host>:<port>/#token=<令牌>。浏览器在挂载前把片段写入原有 localStorage,再从地址栏去掉 token;刷新后仍然登录。不采用本机回环免密。认证边界不变:继续校验 bearer。
#token=片段不会随 HTTP 请求发给服务器。Which issue(s) this PR fixes:
Fixes #88 (#88)
Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.):
被测提交:
5a19874ccf3164b63ad470b076f45d13d961e805(与本 PR head 一致)。基线origin/main@2106e9ecfc9db7dc5cbcacc5ab96c0f8b60b3064。隔离本机栈(未占用默认试用端口 4310)。pnpm buildpnpm --filter @sciencediscovery/web typecheckpnpm --filter @sciencediscovery/web testgit diff --checknpm run test:mocked -- journey-local-token-onboarding.spec.tsE2E 总判定:PASS
修复前后:未分流时,会话内 401 会叠 Toast/连接标记,任务面板还会再画一条
Unauthorizedalert(中间候选曾 4 PASS / 2 FAIL)。补齐类型透传后 6/6 PASS。单测覆盖:401 不按「Unauthorized」字符串过滤;500 与网络错误仍提示。未重打包单文件二进制;launcher ready URL 由单测与源码启动栈共同覆盖。
界面
中文空令牌:只有 Connection 说明,没有叠加红字。
英文空令牌。
错误令牌:只有一处拒绝提示,底部保存按钮可见。
模型注册表:外部模型 API Key。
打开启动登录链接后进入产品,无认证弹窗。
已有会话令牌失效:只有 Connection。
保存有效令牌后恢复原会话。
Self-checklist:(请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入)