| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(plugins): 统一设置写入互斥并补充并发回归 | 16 天前 | |
fix(mcp): prevent secret loss on key rename and document custom MCP | 22 天前 | |
test(e2e): rewrite the Idea Tree journey for the template + intensity model The journey configured a run through numeric budget inputs the settings pane no longer has, and its stub answered two engine contracts that have since grown. Rewritten against what the product does now. Configuration. 标准 is the intensity whose preset gives the three rounds the journey walks through, and the assessors it inspects exist only in water-treatment-materials/v1, so both selects are load-bearing rather than decorative. maxDepth and the design prompt are pinned through the settings API: no intensity preset touches them and the pane does not offer them, so they set the run up rather than being what the step checks. Numbers. Three rounds still come from the budget, but the budget now comes from the intensity. One candidate per round is now a property of the journey's own stub, since candidatesPerRound is raised to 3 by the preset and the engine takes candidates[:maximumCandidates] — so this run also covers the engine accepting fewer candidates than it asked for. Three candidates times the template's three assessors is still 9 assessments. The progress list names assessors with the template's own label, and that template labels its three with their ids, so the roles read activity / stability / sustainability. Stub. Two contracts had moved past it: - aggregate is validated structurally — six arrays of non-empty strings and a confidence in [0, 1]. A bare text was rejected twice and interrupted the run at round 1 with "strengths must be an array of non-empty strings". - a proposal must name a parent the engine selected this round. Only the first round selects ROOT, so from round 2 the old parentless proposal was rejected with "Proposed parent was not selected for expansion". The stub now reads selectedParentIds and sizes its refinements from that parent's depth, which keeps every candidate leaf on maxDepth — naming the parent means the direction label costs no level of its own. Verified against an isolated stack: the journey passes in 8.7 s, having previously exhausted its 180 s budget in step 1. | 14 天前 | |
fix(execution): remove retired tool guidance from prompts and journeys | 22 天前 | |
!181 merge feat/node-native-agent-loop into master refactor: 将 agent 循环原生化到 Node 控制面,退役 gateway 转接层 Created-by: wang_cheng_zhao Commit-by: wang_cheng_zhao Merged-by: wang_cheng_zhao Description: **What type of PR is this?** /kind refactor --- **What does this PR do / why do we need it**: 把 agent 循环从「Node 转交给 Python gateway,由 LangChain create_agent 驱动」改成 **Node 控制面进程内的原生实现**,并把配套的 e2e 用户旅程体系和文档一并补齐。共 10 个提交、99 个文件。 **为什么要做**:原架构下一轮对话要跨两个进程——Node POST {gateway}/run 把 prompt/tools/model/历史发给 Python 侧车,侧车用 LangChain 组环,模型每次调工具再 HTTP 回调 Node 的 /internal/tool-exec。这带来三个长期成本:循环行为受 vendor(deer-flow / LangChain)版本牵制、provider 怪癖要靠额外的模型补丁层兜、以及一条只为传工具结果存在的回调通道和 per-run token 机制。 **改动分三层**: 1. **gateway 内部原生化**(45afe2b) 把 _engine/ 的 agent、model、MCP 接缝在 LangChain 公共 API 上重新实现,保持每个接缝签名与线上契约不变:deferred 工具目录与 tool_search、promotion 状态、摘要与 durable-context、thought_signature 重放、远程内容 tag 净化、基于 langchain-mcp-adapters 的原生 MCP 装载。agent 路径自此不再 import vendor 包。 2. **Node 原生 agent loop**(8efa46f) 新增 services/api/src/native-agent/,删除 gateway-agent.ts(含测试共 1430 行): - index.ts — 循环状态机:流式一轮模型 → 逐字保存 assistant 消息 → 并发执行 tool call、按调用顺序回填 → 再轮,直到某轮不产生 tool call。双计时器(单轮总时长 / 无进展 240s)配合 beginExternalWait 的嵌套暂停,取消与超时分类保持既有语义;重复工具调用 10 次警告、20 次硬停。 - model-client.ts — 直接用 undici 出站,支持 OpenAI 兼容与 Anthropic Messages 两种方言,归一化到同一份 wire 历史;重试只覆盖流开始前的失败。 - deferred-tools.ts / compaction.ts — 延迟工具发现与滚动摘要 checkpoint,格式与旧引擎一致,旧会话历史仍可解析。 - mcp/node-client.ts — 用官方 MCP TypeScript SDK 在进程内直连 stdio / SSE / streamable-HTTP,替掉 gateway HTTP 跳,治理契约(McpInvokeRequest / McpInvokeResponse)不变。 **契约保持不变**:工具实现、权限门、沙箱执行、溯源仍是 packages/agent-runtime 的 createWorkspaceTools 加 API 注入的处理器;SSE AgentEvent 事件面、超时措辞、子 Agent timed_out 判定、finalMessages 交接语义均未变动。因为 assistant 消息逐字保存,provider 怪癖(如 Gemini thought_signature)天然回放,不再需要模型补丁层。 3. **e2e 与文档** - e2e(6 个提交):新增按用户旅程组织的 Playwright 场景与逐步骤报告、网络守卫、journey helper 与 .e2e 装配校验。 - 文档(d2fd2bc):agent-backend.md 按真实模块重写(每节写职责、关键类型/函数、输入输出、失败行为、与权限/工具/溯源的接缝),architecture.md 重画进程图,并同步 control-plane、subagent-orchestration、science-connectors、mcp-tool-protocol、skill-progressive-disclosure、repository-layout、builtin-tools、configuration、web-tools,中英对齐。 **本 PR 未做**(有意保留):web_search / web_fetch 的 provider 执行仍留在 gateway 侧车,仍依赖 vendor 实现,文档已显式标注,未假装已原生化;deer-flow 子模块未删除。 --- **Which issue(s) this PR fixes**: 无对应 issue(架构重构,非缺陷修复)。 --- **Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.)**: 实现与复验由不同角色分别执行,以下为独立复跑结果,并标注各自的被测 commit。 | 范围 | 命令 | 被测 SHA | 结果 | |---|---|---|---| | API 单测全量 | cd services/api && pnpm test | 8efa46f | **429/429 通过,0 失败** | | 原生 loop 定向单测 | node --test dist/native-agent/{native-agent,model-client}.test.js dist/mcp/node-client.test.js | 8efa46f | **21/21 通过** | | 构建与类型检查 | rm -rf services/api/dist && pnpm build | 8efa46f | 通过(含 tsc) | | Gateway Python 套件 | cd services/gateway && python -m unittest discover -s tests | 45afe2b | **137/137 通过**(此后 gateway 代码无改动) | | Gateway smoke | ./test/gateway/run_m0_smoke.sh | 45afe2b | PASS:组装 + 外部工具回调 + 流式 | | Agent loop smoke | ./test/api/run_m1_smoke.sh | 8efa46f | PASS:原生 loop + 流式模型传输 + 真实工具往返 + 多轮历史 | | mocked e2e(隔离栈 4420/4421/4422) | playwright test --config test/playwright.config.ts --grep "@mocked" | 8efa46f | **5 过 / 1 失败 / 1 跳过** | | 文档链接校验 | 全库 Markdown 内部链接扫描 | d2fd2bc | 0 处失效 | **回归判定**:agent 路径已无 vendor 依赖——services/gateway/src 中 deerflow / openjiuwen 仅剩 _engine/web.py 的惰性导入(web provider 专用);services/api/src 中 deerflow / jiuwen / langchain / create_agent **零命中**;POST {gateway}/run 在 Node 侧已无调用方。 **唯一的 e2e 失败是预存产品缺口,非本次回归**:J4(委派子任务旅程)第 5 步断言项目产物目录里应同时出现主 Agent 与子 Agent 的交付物,实际只有 1 份。该用例在 spec 的 preconditions 里就写明「已知缺口 F5,本旅程预期为 FAIL,断言不降级」。已对比基线 0925571(仍走 gateway loop)与 8efa46f(原生 loop)的同一步截图,产物目录内容完全一致,且前 4 步(委派、Subagent 卡片、展开核对过程、主/子职责分离)在原生 loop 下全部通过。 **另有一条与本 PR 无关的基线失败**:packages/agent-runtime 的 runtime.test.ts:146 断言提示词含 [evN]/[aN],而 runtime.ts:213 早已改为 [evidenceN]/[artifactN](由更早的 alias 格式收敛提交造成,断言未同步)。git diff 显示本分支对 packages/ 零改动,且该失败在当前 master 上即可复现,故未在本 PR 内一并修改。 --- **Self-checklist**:(**请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入**) + - [ ] **设计**:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改 + - [x] **测试**:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库 + - [x] **验证**:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述 + - [ ] **接口**:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确 + - [x] **文档**:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓 关于未勾选项的说明: - **设计**:本次重构尚未走 Maintainer 方案评审流程,需要评审后再补勾。 - **接口**:产品对外的 REST / SSE 接口面未变更。变化的是两个内部接缝——gateway POST /run 在 Node 侧已无调用方(路由本身尚未清理),POST /internal/tool-exec 回调随原生化取消(SCIENCE_AGENT_TOOL_CALLBACK_URL 仍被解析但已无人消费)。如需按对外接口口径评审,请指出。 **残留风险**: 1. web_search / web_fetch 的 provider 执行仍在 gateway 侧车,仍依赖 vendor 实现,未原生化。 2. J4 的 F5 缺口描述方向与实测现象相反(spec 写「子 Agent 产物不进目录」,实测缺的是主 Agent 的 results/final.md),建议后续订正,以免误导修复者。 3. gateway POST /run 属死接口,待后续清理。 See merge request: mindspore/ScienceAgent!181 | 1 个月前 | |
chore(rename): 库内第一方 scienceagent 自称改为 sciencediscovery 覆盖容器与沙箱路径(/opt/sciencediscovery、/run/sciencediscovery、 egress 与 python-packages 挂载)、compose 服务与镜像名、CI 镜像与缓存 目录、发布元数据(payload magic、product、单文件与 micromamba 包名)、 API health 与 MCP 客户端名、环境快照 format 标识、工作区 .sciencediscovery 目录、默认 runner/memory-graph 内部 token、文档与测试夹具。 以下改名涉及已有本地数据或历史记录,按既有兼容契约保留旧名读取并打日志: - gateway 环境标记 .sciencediscovery-bootstrap.json 仍读旧文件名,避免 升级触发一次完整重装 - 历史压缩 checkpoint 标记与 additional_kwargs 键仍识别旧拼写,避免旧 会话被重复摘要 - Web localStorage 的 token、语言、工作区布局与 CSV 图表缓存键一次性 导入旧键 - antibody skill 的 ANTIBODY_REQUIRE_SCIENCEDISCOVERY_ENV 仍回退旧变量名 保留不改:launcher 的 science-agent-data / ~/.cache/science-agent 迁移 源路径、已停用默认 token 断言,它们指代的就是旧名本身。 | 1 个月前 | |
feat(auth): print local service sign-in URLs at startup | 13 天前 | |
chore(rename): 补齐 science_agent 形式的第一方自称 仓内 skill 说明、仓库结构文档树根、E2E 用例说明与不可用提示中的 science_agent 改为 ScienceDiscovery / sciencediscovery;antibody workload adapter 的 importlib 模块别名一并改名。 这些位置此前被检索遗漏:同一行还含 SCIENCE_AGENT_* 变量名时被过滤规则 整行丢弃,改用不丢行的正则复检后补上。 | 1 个月前 | |
chore(npm): 第一方包改名为 sciencediscovery 作用域 仓根包名 science-agent 改为 sciencediscovery,17 个 workspace 包 @science-agent/* 改为 @sciencediscovery/*,同步全部 import、 pnpm --filter 调用、架构检查断言、发布脚本与 pnpm-lock.yaml。 e2e 测试工程 science-agent-e2e 一并改名并更新 CI 缓存根目录。 | 1 个月前 | |
chore(npm): 第一方包改名为 sciencediscovery 作用域 仓根包名 science-agent 改为 sciencediscovery,17 个 workspace 包 @science-agent/* 改为 @sciencediscovery/*,同步全部 import、 pnpm --filter 调用、架构检查断言、发布脚本与 pnpm-lock.yaml。 e2e 测试工程 science-agent-e2e 一并改名并更新 CI 缓存根目录。 | 1 个月前 | |
chore(rename): 库内第一方 scienceagent 自称改为 sciencediscovery 覆盖容器与沙箱路径(/opt/sciencediscovery、/run/sciencediscovery、 egress 与 python-packages 挂载)、compose 服务与镜像名、CI 镜像与缓存 目录、发布元数据(payload magic、product、单文件与 micromamba 包名)、 API health 与 MCP 客户端名、环境快照 format 标识、工作区 .sciencediscovery 目录、默认 runner/memory-graph 内部 token、文档与测试夹具。 以下改名涉及已有本地数据或历史记录,按既有兼容契约保留旧名读取并打日志: - gateway 环境标记 .sciencediscovery-bootstrap.json 仍读旧文件名,避免 升级触发一次完整重装 - 历史压缩 checkpoint 标记与 additional_kwargs 键仍识别旧拼写,避免旧 会话被重复摘要 - Web localStorage 的 token、语言、工作区布局与 CSV 图表缓存键一次性 导入旧键 - antibody skill 的 ANTIBODY_REQUIRE_SCIENCEDISCOVERY_ENV 仍回退旧变量名 保留不改:launcher 的 science-agent-data / ~/.cache/science-agent 迁移 源路径、已停用默认 token 断言,它们指代的就是旧名本身。 | 1 个月前 | |
first commit | 1 个月前 | |
first commit | 1 个月前 | |
feat(web): replace composer approval dropdown with a cycling icon toggle The approvals control is no longer a <select>. A single icon button now shows the current mode (shield-check for ask, shield-off for always allow), explains it on hover, and cycles between ask_for_dangerous and always_allow on click via the existing dedicated approvalMode PATCH. The toggle lives directly in the composer footer instead of .orchestration-controls, so the compact running layout keeps it visible and clickable while data sources, specialist, and the keyboard hint stay hidden. Archived sessions keep the control disabled. Geometry E2E expectations follow the new control shape: one remaining select plus the approval toggle in the narrow-viewport height band, and the send-button overlap check now measures the toggle. | 28 天前 | |
first commit | 1 个月前 | |
first commit | 1 个月前 | |
refactor(plan): use lightweight run snapshots | 21 天前 | |
feat(web): show a runtime wake as records that open the execution The runtime notice card had only counts and the model-facing prompt to show, so expanding it printed "[Execution notifications] … Do not replay the command" and a JSON list of execution ids into the conversation, in English whatever the interface language. Deliver the records beside the prompt: RuntimeNotice.records names each delivered execution (owner, Runner, recorded outcome) or reminder (its text), filled from the owner's execution catalog when the wake is queued. The card now reads as a summary — how many results, how many completed or failed, which execution on which Runner for the main Agent or a SubAgent named by its task — and every entry opens the matching record in the activity panel, which learns to reveal a fold and a record on request. The prompt stays in the persisted message and run for diagnosis and is no longer rendered. Notices persisted before the records existed keep their count summary. | 13 天前 | |
test(e2e): cover foreground delivery, background wakes and the notice card Three user journeys on the isolated stack: a Session whose shell work all ran in the foreground stays quiet after its run and its SubAgent stays completed while the running card showed progress; a background: true execution still wakes its owner exactly once and leaves a readable notice that opens the execution record; and a completed SubAgent is still woken by its own unread background result, in its own context, without losing its completed record. | 13 天前 | |
fix(web): clarify workspace disclosure state and localized labels | 19 天前 | |
修复 UT 托管执行清理竞态,并让旅程断言跟上界面重构 UT:workspace-bindings 的两条 NPU 链路用例,跑完四种执行方式后立刻删掉临时 数据目录,报 ENOTEMPTY: directory not empty, rmdir '<dataDir>/versioning'。 四种里只有托管 Shell 不在自己的调用里跑完:ShellExecutions.start() 在 Runner 接受提交时就返回,把余下的生命周期留在 store 记在 active 里的后台 Promise 上,而 execution.resultRef 的溯源写入正落在 <dataDir>/versioning。清理与写入 因此并发,rm(2) 看到刚清空的目录又冒出条目。改成删除前 await shellExecutions.wait(),等的就是那个后台 Promise。旁边只跑一次执行、从不调 start 的第三条用例一直是绿的,可作对照。 E2E:设置二级目录、工作区分区、过程记录三次重构改了用户实际看到的界面, 旅程的断言没有同步,九条用例失败。逐条对上现在的实现: MCP 测试连接的提示改用 mcp.testPassedNamed(“{name}:测试通过 (N ms)”), 三份 spec 断言的“连接成功”是另一个 key mcp.testPassed 的值,后者在 web 端 已无人引用。连接本身是成功的——反馈元素带的就是 success 类。 产物目录改成 artifacts.length > 0 才渲染,openArtifactPanel 却无条件断言它 可见,而 J2 和 J8 的第一步恰恰是“确认还没有任何产物”。新增 expectNoArtifactCatalog 表达这个状态:没有产物时整段不存在,而不是显示 0。 窄屏(≤900px)下 .settings-group-nav 是 display:none,收在“设置目录”按钮 后面,分组按钮随之离开可访问性树,两处 openModelRegistry 直接点它只会等到 用例超时。按 openEnvironmentPage 已有的写法,先判断导航是否可见。 活动面板拆成执行、传输、提醒三个并列折叠区,其中每条记录又是一个折叠区, 且只在任务运行时自动展开。用例只点了第一个 summary,于是传输里的“已提交 文件数”在 DOM 里但不可见;取消之后记录收起,按钮也随之消失。改为按需展开, 并把取消后的状态断言在标题行上。清空任务后三个折叠区整体消失,不再有 “暂无执行”空态,空状态断言一并对齐。 J6 第 7 步是更早就存在的失败,与上面三次重构无关:删除模型走 window.confirm, Playwright 会替无人监听的对话框选择取消,DELETE 请求从未发出,用例却在等一 条服务端错误提示。按仓内其他旅程的做法补上 dialog 监听。 | 17 天前 | |
feat(web): simplify process records and organize workspace sections | 19 天前 | |
fix(web): align artifact tabs and simplify workspace file label | 15 天前 | |
修复 UT 托管执行清理竞态,并让旅程断言跟上界面重构 UT:workspace-bindings 的两条 NPU 链路用例,跑完四种执行方式后立刻删掉临时 数据目录,报 ENOTEMPTY: directory not empty, rmdir '<dataDir>/versioning'。 四种里只有托管 Shell 不在自己的调用里跑完:ShellExecutions.start() 在 Runner 接受提交时就返回,把余下的生命周期留在 store 记在 active 里的后台 Promise 上,而 execution.resultRef 的溯源写入正落在 <dataDir>/versioning。清理与写入 因此并发,rm(2) 看到刚清空的目录又冒出条目。改成删除前 await shellExecutions.wait(),等的就是那个后台 Promise。旁边只跑一次执行、从不调 start 的第三条用例一直是绿的,可作对照。 E2E:设置二级目录、工作区分区、过程记录三次重构改了用户实际看到的界面, 旅程的断言没有同步,九条用例失败。逐条对上现在的实现: MCP 测试连接的提示改用 mcp.testPassedNamed(“{name}:测试通过 (N ms)”), 三份 spec 断言的“连接成功”是另一个 key mcp.testPassed 的值,后者在 web 端 已无人引用。连接本身是成功的——反馈元素带的就是 success 类。 产物目录改成 artifacts.length > 0 才渲染,openArtifactPanel 却无条件断言它 可见,而 J2 和 J8 的第一步恰恰是“确认还没有任何产物”。新增 expectNoArtifactCatalog 表达这个状态:没有产物时整段不存在,而不是显示 0。 窄屏(≤900px)下 .settings-group-nav 是 display:none,收在“设置目录”按钮 后面,分组按钮随之离开可访问性树,两处 openModelRegistry 直接点它只会等到 用例超时。按 openEnvironmentPage 已有的写法,先判断导航是否可见。 活动面板拆成执行、传输、提醒三个并列折叠区,其中每条记录又是一个折叠区, 且只在任务运行时自动展开。用例只点了第一个 summary,于是传输里的“已提交 文件数”在 DOM 里但不可见;取消之后记录收起,按钮也随之消失。改为按需展开, 并把取消后的状态断言在标题行上。清空任务后三个折叠区整体消失,不再有 “暂无执行”空态,空状态断言一并对齐。 J6 第 7 步是更早就存在的失败,与上面三次重构无关:删除模型走 window.confirm, Playwright 会替无人监听的对话框选择取消,DELETE 请求从未发出,用例却在等一 条服务端错误提示。按仓内其他旅程的做法补上 dialog 监听。 | 17 天前 | |
test(e2e): follow two UI strings that moved into the message catalogue E2E (mocked) went red on the mirror with 4 journeys failing and the job taking 16.6 minutes. Two root causes, one class: a UI string moved from a component's hardcoded Chinese into the message catalogue, and journeys that located elements by the old text stopped finding them. Most then burned their whole test budget, so the failures surfaced as timeouts and did not read like a wording problem at all. The provider editor's credential field. The local-token onboarding work renamed it from "LLM API 令牌" to "外部模型 API Key" / "External model API Key", deliberately, so a model provider's key reads as distinct from the local service access token. The journey added with that change uses the new label; three older ones were left on the old one: waiting for getByRole('dialog', { name: '系统设置' }) .getByRole('region', { name: '服务商编辑器' }) .getByLabel('LLM API 令牌') 服务商编辑器 and 服务商名称 resolve in that same chain, so the page is Chinese and only this one label is gone — a rename, not a locale problem. journey-model-settings failed its visibility check outright, while journey-first-run and journey-provider-model-catalog blocked on fill for 3 and 4 minutes, which is where the job's 16.6 minutes went. Nine call sites across the three files take the new label; all three already pin locale: "zh-CN", and no other assertion changed. The Idea Tree journey's locale. It reads the research surface in Chinese from end to end but never said so, which worked while those strings were hardcoded and rendered Chinese in any locale. They are catalogue entries now, and Playwright gives Chromium en-US by default, so detectLocale() picks en and the first select is looked up under a label the page never renders. Everything after it was equally exposed: ideaResearch.controlsAria, progressAria, viewProgress, the pause/continue/end controls and every status word come from the catalogue too. test.use({ locale: "zh-CN" }) covers all of them and matches the three journeys above. The option values it selects — water-treatment-materials/v1 and standard — are locale-independent and unchanged. Only Playwright specs change here; no product code. Verified on this commit: pnpm ci:ut exit 0 (2676 Node passed / 0 failed / 8 skipped; evolve 316 passed; memory-graph 83 passed / 77 skipped; gateway 26 tests OK; paper 2 tests OK), pnpm ci:st exit 0 (agent loop smoke PASS), pnpm ci:e2e exit 0 (39 passed / 0 failed / 2 skipped; check-e2e-meta 44 spec files, 0 errors, 11 legacy warnings — unchanged). The four journeys also pass individually: 12.5 s, 6.5 s, 28.8 s and 8.8 s, against 3 min, 10 s, 4 min and 180 s of failure before. | 11 天前 | |
test(e2e): follow two UI strings that moved into the message catalogue E2E (mocked) went red on the mirror with 4 journeys failing and the job taking 16.6 minutes. Two root causes, one class: a UI string moved from a component's hardcoded Chinese into the message catalogue, and journeys that located elements by the old text stopped finding them. Most then burned their whole test budget, so the failures surfaced as timeouts and did not read like a wording problem at all. The provider editor's credential field. The local-token onboarding work renamed it from "LLM API 令牌" to "外部模型 API Key" / "External model API Key", deliberately, so a model provider's key reads as distinct from the local service access token. The journey added with that change uses the new label; three older ones were left on the old one: waiting for getByRole('dialog', { name: '系统设置' }) .getByRole('region', { name: '服务商编辑器' }) .getByLabel('LLM API 令牌') 服务商编辑器 and 服务商名称 resolve in that same chain, so the page is Chinese and only this one label is gone — a rename, not a locale problem. journey-model-settings failed its visibility check outright, while journey-first-run and journey-provider-model-catalog blocked on fill for 3 and 4 minutes, which is where the job's 16.6 minutes went. Nine call sites across the three files take the new label; all three already pin locale: "zh-CN", and no other assertion changed. The Idea Tree journey's locale. It reads the research surface in Chinese from end to end but never said so, which worked while those strings were hardcoded and rendered Chinese in any locale. They are catalogue entries now, and Playwright gives Chromium en-US by default, so detectLocale() picks en and the first select is looked up under a label the page never renders. Everything after it was equally exposed: ideaResearch.controlsAria, progressAria, viewProgress, the pause/continue/end controls and every status word come from the catalogue too. test.use({ locale: "zh-CN" }) covers all of them and matches the three journeys above. The option values it selects — water-treatment-materials/v1 and standard — are locale-independent and unchanged. Only Playwright specs change here; no product code. Verified on this commit: pnpm ci:ut exit 0 (2676 Node passed / 0 failed / 8 skipped; evolve 316 passed; memory-graph 83 passed / 77 skipped; gateway 26 tests OK; paper 2 tests OK), pnpm ci:st exit 0 (agent loop smoke PASS), pnpm ci:e2e exit 0 (39 passed / 0 failed / 2 skipped; check-e2e-meta 44 spec files, 0 errors, 11 legacy warnings — unchanged). The four journeys also pass individually: 12.5 s, 6.5 s, 28.8 s and 8.8 s, against 3 min, 10 s, 4 min and 180 s of failure before. | 11 天前 | |
修复 UT 托管执行清理竞态,并让旅程断言跟上界面重构 UT:workspace-bindings 的两条 NPU 链路用例,跑完四种执行方式后立刻删掉临时 数据目录,报 ENOTEMPTY: directory not empty, rmdir '<dataDir>/versioning'。 四种里只有托管 Shell 不在自己的调用里跑完:ShellExecutions.start() 在 Runner 接受提交时就返回,把余下的生命周期留在 store 记在 active 里的后台 Promise 上,而 execution.resultRef 的溯源写入正落在 <dataDir>/versioning。清理与写入 因此并发,rm(2) 看到刚清空的目录又冒出条目。改成删除前 await shellExecutions.wait(),等的就是那个后台 Promise。旁边只跑一次执行、从不调 start 的第三条用例一直是绿的,可作对照。 E2E:设置二级目录、工作区分区、过程记录三次重构改了用户实际看到的界面, 旅程的断言没有同步,九条用例失败。逐条对上现在的实现: MCP 测试连接的提示改用 mcp.testPassedNamed(“{name}:测试通过 (N ms)”), 三份 spec 断言的“连接成功”是另一个 key mcp.testPassed 的值,后者在 web 端 已无人引用。连接本身是成功的——反馈元素带的就是 success 类。 产物目录改成 artifacts.length > 0 才渲染,openArtifactPanel 却无条件断言它 可见,而 J2 和 J8 的第一步恰恰是“确认还没有任何产物”。新增 expectNoArtifactCatalog 表达这个状态:没有产物时整段不存在,而不是显示 0。 窄屏(≤900px)下 .settings-group-nav 是 display:none,收在“设置目录”按钮 后面,分组按钮随之离开可访问性树,两处 openModelRegistry 直接点它只会等到 用例超时。按 openEnvironmentPage 已有的写法,先判断导航是否可见。 活动面板拆成执行、传输、提醒三个并列折叠区,其中每条记录又是一个折叠区, 且只在任务运行时自动展开。用例只点了第一个 summary,于是传输里的“已提交 文件数”在 DOM 里但不可见;取消之后记录收起,按钮也随之消失。改为按需展开, 并把取消后的状态断言在标题行上。清空任务后三个折叠区整体消失,不再有 “暂无执行”空态,空状态断言一并对齐。 J6 第 7 步是更早就存在的失败,与上面三次重构无关:删除模型走 window.confirm, Playwright 会替无人监听的对话框选择取消,DELETE 请求从未发出,用例却在等一 条服务端错误提示。按仓内其他旅程的做法补上 dialog 监听。 | 17 天前 | |
test(auth): cover expired tokens in existing sessions | 13 天前 | |
修复 UT 托管执行清理竞态,并让旅程断言跟上界面重构 UT:workspace-bindings 的两条 NPU 链路用例,跑完四种执行方式后立刻删掉临时 数据目录,报 ENOTEMPTY: directory not empty, rmdir '<dataDir>/versioning'。 四种里只有托管 Shell 不在自己的调用里跑完:ShellExecutions.start() 在 Runner 接受提交时就返回,把余下的生命周期留在 store 记在 active 里的后台 Promise 上,而 execution.resultRef 的溯源写入正落在 <dataDir>/versioning。清理与写入 因此并发,rm(2) 看到刚清空的目录又冒出条目。改成删除前 await shellExecutions.wait(),等的就是那个后台 Promise。旁边只跑一次执行、从不调 start 的第三条用例一直是绿的,可作对照。 E2E:设置二级目录、工作区分区、过程记录三次重构改了用户实际看到的界面, 旅程的断言没有同步,九条用例失败。逐条对上现在的实现: MCP 测试连接的提示改用 mcp.testPassedNamed(“{name}:测试通过 (N ms)”), 三份 spec 断言的“连接成功”是另一个 key mcp.testPassed 的值,后者在 web 端 已无人引用。连接本身是成功的——反馈元素带的就是 success 类。 产物目录改成 artifacts.length > 0 才渲染,openArtifactPanel 却无条件断言它 可见,而 J2 和 J8 的第一步恰恰是“确认还没有任何产物”。新增 expectNoArtifactCatalog 表达这个状态:没有产物时整段不存在,而不是显示 0。 窄屏(≤900px)下 .settings-group-nav 是 display:none,收在“设置目录”按钮 后面,分组按钮随之离开可访问性树,两处 openModelRegistry 直接点它只会等到 用例超时。按 openEnvironmentPage 已有的写法,先判断导航是否可见。 活动面板拆成执行、传输、提醒三个并列折叠区,其中每条记录又是一个折叠区, 且只在任务运行时自动展开。用例只点了第一个 summary,于是传输里的“已提交 文件数”在 DOM 里但不可见;取消之后记录收起,按钮也随之消失。改为按需展开, 并把取消后的状态断言在标题行上。清空任务后三个折叠区整体消失,不再有 “暂无执行”空态,空状态断言一并对齐。 J6 第 7 步是更早就存在的失败,与上面三次重构无关:删除模型走 window.confirm, Playwright 会替无人监听的对话框选择取消,DELETE 请求从未发出,用例却在等一 条服务端错误提示。按仓内其他旅程的做法补上 dialog 监听。 | 17 天前 | |
修复 UT 托管执行清理竞态,并让旅程断言跟上界面重构 UT:workspace-bindings 的两条 NPU 链路用例,跑完四种执行方式后立刻删掉临时 数据目录,报 ENOTEMPTY: directory not empty, rmdir '<dataDir>/versioning'。 四种里只有托管 Shell 不在自己的调用里跑完:ShellExecutions.start() 在 Runner 接受提交时就返回,把余下的生命周期留在 store 记在 active 里的后台 Promise 上,而 execution.resultRef 的溯源写入正落在 <dataDir>/versioning。清理与写入 因此并发,rm(2) 看到刚清空的目录又冒出条目。改成删除前 await shellExecutions.wait(),等的就是那个后台 Promise。旁边只跑一次执行、从不调 start 的第三条用例一直是绿的,可作对照。 E2E:设置二级目录、工作区分区、过程记录三次重构改了用户实际看到的界面, 旅程的断言没有同步,九条用例失败。逐条对上现在的实现: MCP 测试连接的提示改用 mcp.testPassedNamed(“{name}:测试通过 (N ms)”), 三份 spec 断言的“连接成功”是另一个 key mcp.testPassed 的值,后者在 web 端 已无人引用。连接本身是成功的——反馈元素带的就是 success 类。 产物目录改成 artifacts.length > 0 才渲染,openArtifactPanel 却无条件断言它 可见,而 J2 和 J8 的第一步恰恰是“确认还没有任何产物”。新增 expectNoArtifactCatalog 表达这个状态:没有产物时整段不存在,而不是显示 0。 窄屏(≤900px)下 .settings-group-nav 是 display:none,收在“设置目录”按钮 后面,分组按钮随之离开可访问性树,两处 openModelRegistry 直接点它只会等到 用例超时。按 openEnvironmentPage 已有的写法,先判断导航是否可见。 活动面板拆成执行、传输、提醒三个并列折叠区,其中每条记录又是一个折叠区, 且只在任务运行时自动展开。用例只点了第一个 summary,于是传输里的“已提交 文件数”在 DOM 里但不可见;取消之后记录收起,按钮也随之消失。改为按需展开, 并把取消后的状态断言在标题行上。清空任务后三个折叠区整体消失,不再有 “暂无执行”空态,空状态断言一并对齐。 J6 第 7 步是更早就存在的失败,与上面三次重构无关:删除模型走 window.confirm, Playwright 会替无人监听的对话框选择取消,DELETE 请求从未发出,用例却在等一 条服务端错误提示。按仓内其他旅程的做法补上 dialog 监听。 | 17 天前 | |
适配设置目录旅程并修正科学环境测试前置状态 | 18 天前 | |
test(e2e): follow two UI strings that moved into the message catalogue E2E (mocked) went red on the mirror with 4 journeys failing and the job taking 16.6 minutes. Two root causes, one class: a UI string moved from a component's hardcoded Chinese into the message catalogue, and journeys that located elements by the old text stopped finding them. Most then burned their whole test budget, so the failures surfaced as timeouts and did not read like a wording problem at all. The provider editor's credential field. The local-token onboarding work renamed it from "LLM API 令牌" to "外部模型 API Key" / "External model API Key", deliberately, so a model provider's key reads as distinct from the local service access token. The journey added with that change uses the new label; three older ones were left on the old one: waiting for getByRole('dialog', { name: '系统设置' }) .getByRole('region', { name: '服务商编辑器' }) .getByLabel('LLM API 令牌') 服务商编辑器 and 服务商名称 resolve in that same chain, so the page is Chinese and only this one label is gone — a rename, not a locale problem. journey-model-settings failed its visibility check outright, while journey-first-run and journey-provider-model-catalog blocked on fill for 3 and 4 minutes, which is where the job's 16.6 minutes went. Nine call sites across the three files take the new label; all three already pin locale: "zh-CN", and no other assertion changed. The Idea Tree journey's locale. It reads the research surface in Chinese from end to end but never said so, which worked while those strings were hardcoded and rendered Chinese in any locale. They are catalogue entries now, and Playwright gives Chromium en-US by default, so detectLocale() picks en and the first select is looked up under a label the page never renders. Everything after it was equally exposed: ideaResearch.controlsAria, progressAria, viewProgress, the pause/continue/end controls and every status word come from the catalogue too. test.use({ locale: "zh-CN" }) covers all of them and matches the three journeys above. The option values it selects — water-treatment-materials/v1 and standard — are locale-independent and unchanged. Only Playwright specs change here; no product code. Verified on this commit: pnpm ci:ut exit 0 (2676 Node passed / 0 failed / 8 skipped; evolve 316 passed; memory-graph 83 passed / 77 skipped; gateway 26 tests OK; paper 2 tests OK), pnpm ci:st exit 0 (agent loop smoke PASS), pnpm ci:e2e exit 0 (39 passed / 0 failed / 2 skipped; check-e2e-meta 44 spec files, 0 errors, 11 legacy warnings — unchanged). The four journeys also pass individually: 12.5 s, 6.5 s, 28.8 s and 8.8 s, against 3 min, 10 s, 4 min and 180 s of failure before. | 11 天前 | |
适配设置目录旅程并修正科学环境测试前置状态 | 18 天前 | |
feat(web): simplify process records and organize workspace sections | 19 天前 | |
fix(web): apply connector plugin gates consistently in composer | 16 天前 | |
修复科学环境旅程 J3 失效的入口、接口路径与工具参数 设置侧栏改成 Runner 树之后,环境不再是独立的设置分组,openEnvironmentPage 要点的那个按钮已经不渲染,J3 从第一步就进不去。改成在 Runner 目录里选本机 再切到科学环境页签;该页是紧凑布局,安装状态和全局软件包源都在折叠区里, 补一个展开折叠区的辅助函数,让这两步断言的是用户真正看得见的内容。 界面上的环境创建和删除现在走带 Runner 前缀的接口,两处 waitForResponse 的 路径同步改成 /api/runners/local/environments。 run_shell 的工具参数是 environment_id,旅程的模型 stub 传的是 environmentId, 于是那次计算其实退回系统 shell 执行、python 不存在、退出码 127;而断言只在 工具卡片里匹配标记文本,输入区就能匹配上,这处失效不会让旅程变红。改正参数 名,并要求工具卡片不是失败态。 溯源那步原本查找 details[aria-label='Provenance record'],该折叠区已随 48fbdb5a 从工作区面板移除,时间线不再展示某次执行用的是哪个环境;改为核对 这次执行留下的记录:成功结束、退出码 0、环境修订正是刚创建的那个。 隔离栈实跑:J3 与 R1 都通过。 | 18 天前 | |
test(e2e): follow two UI strings that moved into the message catalogue E2E (mocked) went red on the mirror with 4 journeys failing and the job taking 16.6 minutes. Two root causes, one class: a UI string moved from a component's hardcoded Chinese into the message catalogue, and journeys that located elements by the old text stopped finding them. Most then burned their whole test budget, so the failures surfaced as timeouts and did not read like a wording problem at all. The provider editor's credential field. The local-token onboarding work renamed it from "LLM API 令牌" to "外部模型 API Key" / "External model API Key", deliberately, so a model provider's key reads as distinct from the local service access token. The journey added with that change uses the new label; three older ones were left on the old one: waiting for getByRole('dialog', { name: '系统设置' }) .getByRole('region', { name: '服务商编辑器' }) .getByLabel('LLM API 令牌') 服务商编辑器 and 服务商名称 resolve in that same chain, so the page is Chinese and only this one label is gone — a rename, not a locale problem. journey-model-settings failed its visibility check outright, while journey-first-run and journey-provider-model-catalog blocked on fill for 3 and 4 minutes, which is where the job's 16.6 minutes went. Nine call sites across the three files take the new label; all three already pin locale: "zh-CN", and no other assertion changed. The Idea Tree journey's locale. It reads the research surface in Chinese from end to end but never said so, which worked while those strings were hardcoded and rendered Chinese in any locale. They are catalogue entries now, and Playwright gives Chromium en-US by default, so detectLocale() picks en and the first select is looked up under a label the page never renders. Everything after it was equally exposed: ideaResearch.controlsAria, progressAria, viewProgress, the pause/continue/end controls and every status word come from the catalogue too. test.use({ locale: "zh-CN" }) covers all of them and matches the three journeys above. The option values it selects — water-treatment-materials/v1 and standard — are locale-independent and unchanged. Only Playwright specs change here; no product code. Verified on this commit: pnpm ci:ut exit 0 (2676 Node passed / 0 failed / 8 skipped; evolve 316 passed; memory-graph 83 passed / 77 skipped; gateway 26 tests OK; paper 2 tests OK), pnpm ci:st exit 0 (agent loop smoke PASS), pnpm ci:e2e exit 0 (39 passed / 0 failed / 2 skipped; check-e2e-meta 44 spec files, 0 errors, 11 legacy warnings — unchanged). The four journeys also pass individually: 12.5 s, 6.5 s, 28.8 s and 8.8 s, against 3 min, 10 s, 4 min and 180 s of failure before. | 11 天前 | |
!181 merge feat/node-native-agent-loop into master refactor: 将 agent 循环原生化到 Node 控制面,退役 gateway 转接层 Created-by: wang_cheng_zhao Commit-by: wang_cheng_zhao Merged-by: wang_cheng_zhao Description: **What type of PR is this?** /kind refactor --- **What does this PR do / why do we need it**: 把 agent 循环从「Node 转交给 Python gateway,由 LangChain create_agent 驱动」改成 **Node 控制面进程内的原生实现**,并把配套的 e2e 用户旅程体系和文档一并补齐。共 10 个提交、99 个文件。 **为什么要做**:原架构下一轮对话要跨两个进程——Node POST {gateway}/run 把 prompt/tools/model/历史发给 Python 侧车,侧车用 LangChain 组环,模型每次调工具再 HTTP 回调 Node 的 /internal/tool-exec。这带来三个长期成本:循环行为受 vendor(deer-flow / LangChain)版本牵制、provider 怪癖要靠额外的模型补丁层兜、以及一条只为传工具结果存在的回调通道和 per-run token 机制。 **改动分三层**: 1. **gateway 内部原生化**(45afe2b) 把 _engine/ 的 agent、model、MCP 接缝在 LangChain 公共 API 上重新实现,保持每个接缝签名与线上契约不变:deferred 工具目录与 tool_search、promotion 状态、摘要与 durable-context、thought_signature 重放、远程内容 tag 净化、基于 langchain-mcp-adapters 的原生 MCP 装载。agent 路径自此不再 import vendor 包。 2. **Node 原生 agent loop**(8efa46f) 新增 services/api/src/native-agent/,删除 gateway-agent.ts(含测试共 1430 行): - index.ts — 循环状态机:流式一轮模型 → 逐字保存 assistant 消息 → 并发执行 tool call、按调用顺序回填 → 再轮,直到某轮不产生 tool call。双计时器(单轮总时长 / 无进展 240s)配合 beginExternalWait 的嵌套暂停,取消与超时分类保持既有语义;重复工具调用 10 次警告、20 次硬停。 - model-client.ts — 直接用 undici 出站,支持 OpenAI 兼容与 Anthropic Messages 两种方言,归一化到同一份 wire 历史;重试只覆盖流开始前的失败。 - deferred-tools.ts / compaction.ts — 延迟工具发现与滚动摘要 checkpoint,格式与旧引擎一致,旧会话历史仍可解析。 - mcp/node-client.ts — 用官方 MCP TypeScript SDK 在进程内直连 stdio / SSE / streamable-HTTP,替掉 gateway HTTP 跳,治理契约(McpInvokeRequest / McpInvokeResponse)不变。 **契约保持不变**:工具实现、权限门、沙箱执行、溯源仍是 packages/agent-runtime 的 createWorkspaceTools 加 API 注入的处理器;SSE AgentEvent 事件面、超时措辞、子 Agent timed_out 判定、finalMessages 交接语义均未变动。因为 assistant 消息逐字保存,provider 怪癖(如 Gemini thought_signature)天然回放,不再需要模型补丁层。 3. **e2e 与文档** - e2e(6 个提交):新增按用户旅程组织的 Playwright 场景与逐步骤报告、网络守卫、journey helper 与 .e2e 装配校验。 - 文档(d2fd2bc):agent-backend.md 按真实模块重写(每节写职责、关键类型/函数、输入输出、失败行为、与权限/工具/溯源的接缝),architecture.md 重画进程图,并同步 control-plane、subagent-orchestration、science-connectors、mcp-tool-protocol、skill-progressive-disclosure、repository-layout、builtin-tools、configuration、web-tools,中英对齐。 **本 PR 未做**(有意保留):web_search / web_fetch 的 provider 执行仍留在 gateway 侧车,仍依赖 vendor 实现,文档已显式标注,未假装已原生化;deer-flow 子模块未删除。 --- **Which issue(s) this PR fixes**: 无对应 issue(架构重构,非缺陷修复)。 --- **Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.)**: 实现与复验由不同角色分别执行,以下为独立复跑结果,并标注各自的被测 commit。 | 范围 | 命令 | 被测 SHA | 结果 | |---|---|---|---| | API 单测全量 | cd services/api && pnpm test | 8efa46f | **429/429 通过,0 失败** | | 原生 loop 定向单测 | node --test dist/native-agent/{native-agent,model-client}.test.js dist/mcp/node-client.test.js | 8efa46f | **21/21 通过** | | 构建与类型检查 | rm -rf services/api/dist && pnpm build | 8efa46f | 通过(含 tsc) | | Gateway Python 套件 | cd services/gateway && python -m unittest discover -s tests | 45afe2b | **137/137 通过**(此后 gateway 代码无改动) | | Gateway smoke | ./test/gateway/run_m0_smoke.sh | 45afe2b | PASS:组装 + 外部工具回调 + 流式 | | Agent loop smoke | ./test/api/run_m1_smoke.sh | 8efa46f | PASS:原生 loop + 流式模型传输 + 真实工具往返 + 多轮历史 | | mocked e2e(隔离栈 4420/4421/4422) | playwright test --config test/playwright.config.ts --grep "@mocked" | 8efa46f | **5 过 / 1 失败 / 1 跳过** | | 文档链接校验 | 全库 Markdown 内部链接扫描 | d2fd2bc | 0 处失效 | **回归判定**:agent 路径已无 vendor 依赖——services/gateway/src 中 deerflow / openjiuwen 仅剩 _engine/web.py 的惰性导入(web provider 专用);services/api/src 中 deerflow / jiuwen / langchain / create_agent **零命中**;POST {gateway}/run 在 Node 侧已无调用方。 **唯一的 e2e 失败是预存产品缺口,非本次回归**:J4(委派子任务旅程)第 5 步断言项目产物目录里应同时出现主 Agent 与子 Agent 的交付物,实际只有 1 份。该用例在 spec 的 preconditions 里就写明「已知缺口 F5,本旅程预期为 FAIL,断言不降级」。已对比基线 0925571(仍走 gateway loop)与 8efa46f(原生 loop)的同一步截图,产物目录内容完全一致,且前 4 步(委派、Subagent 卡片、展开核对过程、主/子职责分离)在原生 loop 下全部通过。 **另有一条与本 PR 无关的基线失败**:packages/agent-runtime 的 runtime.test.ts:146 断言提示词含 [evN]/[aN],而 runtime.ts:213 早已改为 [evidenceN]/[artifactN](由更早的 alias 格式收敛提交造成,断言未同步)。git diff 显示本分支对 packages/ 零改动,且该失败在当前 master 上即可复现,故未在本 PR 内一并修改。 --- **Self-checklist**:(**请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入**) + - [ ] **设计**:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改 + - [x] **测试**:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库 + - [x] **验证**:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述 + - [ ] **接口**:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确 + - [x] **文档**:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓 关于未勾选项的说明: - **设计**:本次重构尚未走 Maintainer 方案评审流程,需要评审后再补勾。 - **接口**:产品对外的 REST / SSE 接口面未变更。变化的是两个内部接缝——gateway POST /run 在 Node 侧已无调用方(路由本身尚未清理),POST /internal/tool-exec 回调随原生化取消(SCIENCE_AGENT_TOOL_CALLBACK_URL 仍被解析但已无人消费)。如需按对外接口口径评审,请指出。 **残留风险**: 1. web_search / web_fetch 的 provider 执行仍在 gateway 侧车,仍依赖 vendor 实现,未原生化。 2. J4 的 F5 缺口描述方向与实测现象相反(spec 写「子 Agent 产物不进目录」,实测缺的是主 Agent 的 results/final.md),建议后续订正,以免误导修复者。 3. gateway POST /run 属死接口,待后续清理。 See merge request: mindspore/ScienceAgent!181 | 1 个月前 | |
test: 隔离自动通知与用户响应旅程 | 19 天前 | |
test(e2e): identify the reviewer timeline card by what it reviewed The card renders the Artifact's logical name, a version line carrying the review level, and a result label. The words "Reviewer Specialist" appear nowhere in it, so asserting that literal string failed against a card that was present and correct: Received string: "›results/report.mdVersion de49a3fa · Quick No applicable checks…" It now asserts the Artifact the audit reviewed and the level it ran at, which ties the timeline entry to the audit rather than to a brand string. ("No applicable checks" is the honest outcome here: the deterministic Quick review of a report with no citations and no computations has nothing to check, so it decides SKIPPED.) Verified against an isolated stack: the journey passes in 1.1 m, the automatic 60 s batching window included. | 14 天前 | |
Fix reviewer evidence presentation | 14 天前 | |
test: align reviewer matrix contradiction label | 14 天前 | |
修正设置目录旅程科学环境模拟数据与软件源选择器 | 18 天前 | |
test(web): disambiguate network settings session fixture | 22 天前 | |
test(e2e): keep the trajectory journey's E2E-META block against its test check-e2e-meta.mjs requires the E2E-META block to be the last thing before a top-level test(, with only // line comments allowed in between. Two documented helpers — ctrlWheelZoom and filterOnlyKind — were added between the block and the test, so the checker read the last /** ... */ before the declaration, found the helper's own doc comment instead, and reported journey-session-trajectory.spec.ts:50: test is not immediately preceded by an E2E-META block. The helpers now sit above the block, which is unchanged and still the declaration's immediate neighbour. This is a pure move: no metadata, no helper and no assertion changed. The drift survived because the CodeArts pipeline does not run the browser E2E layer, so only the GitHub mirror reaches this checker — and there it runs after the stack is healthy but before the journeys, which is why the job failed without executing a single journey. Verified: node test/check-e2e-meta.mjs reports 42 spec file(s), 0 error(s), 11 legacy warning(s); the 11 legacy warnings are unchanged. | 14 天前 | |
重组设置二级目录并按 Runner 管理机器工作区与环境 | 18 天前 | |
test(e2e): synchronize mocked journeys with what the workbench renders Three mocked specs waited for something the product does not do, and none of them had ever run on a pipeline: CodeArts does not run the browser E2E layer, and on the GitHub mirror the layer aborted at check-e2e-meta before starting a journey. journey-reviewer-auto-audit asserted .reviewer-control-card was visible as soon as the Session opened. The card is rendered inside a collapsed details.workspace-fold, like the Agent-activity and Evolve folds beside it, so Playwright found the element 24 times and reported it hidden every time. The step now opens the disclosure first, the way a user reads those controls, and then asserts the card. timeouts-runtime-status waited for networkidle after page.goto("/"). When the workbench restores a Session it starts five per-Session pollers — agent-activity and four mcp/* endpoints, about 30 requests each over the window — so the browser never goes 500 ms without a request and the wait consumed the whole 60 s budget. The trace ends in page.waitForLoadState: Test timeout of 60000ms exceeded, at timeouts-runtime-status.spec.ts:108. It now waits for the shell it is about to click in. Whether a Session is restored depends on what ran before, which is why the spec looked stable. literature-review's openWorkspace carried the same networkidle call as a redundant prefix to an already-correct visible assertion. It passed this round only because no Session had been restored in its context; removing the call leaves the assertion as the wait. Verified: node test/check-e2e-meta.mjs 42 spec file(s), 0 error(s), 11 legacy warning(s) — unchanged. | 14 天前 | |
!181 merge feat/node-native-agent-loop into master refactor: 将 agent 循环原生化到 Node 控制面,退役 gateway 转接层 Created-by: wang_cheng_zhao Commit-by: wang_cheng_zhao Merged-by: wang_cheng_zhao Description: **What type of PR is this?** /kind refactor --- **What does this PR do / why do we need it**: 把 agent 循环从「Node 转交给 Python gateway,由 LangChain create_agent 驱动」改成 **Node 控制面进程内的原生实现**,并把配套的 e2e 用户旅程体系和文档一并补齐。共 10 个提交、99 个文件。 **为什么要做**:原架构下一轮对话要跨两个进程——Node POST {gateway}/run 把 prompt/tools/model/历史发给 Python 侧车,侧车用 LangChain 组环,模型每次调工具再 HTTP 回调 Node 的 /internal/tool-exec。这带来三个长期成本:循环行为受 vendor(deer-flow / LangChain)版本牵制、provider 怪癖要靠额外的模型补丁层兜、以及一条只为传工具结果存在的回调通道和 per-run token 机制。 **改动分三层**: 1. **gateway 内部原生化**(45afe2b) 把 _engine/ 的 agent、model、MCP 接缝在 LangChain 公共 API 上重新实现,保持每个接缝签名与线上契约不变:deferred 工具目录与 tool_search、promotion 状态、摘要与 durable-context、thought_signature 重放、远程内容 tag 净化、基于 langchain-mcp-adapters 的原生 MCP 装载。agent 路径自此不再 import vendor 包。 2. **Node 原生 agent loop**(8efa46f) 新增 services/api/src/native-agent/,删除 gateway-agent.ts(含测试共 1430 行): - index.ts — 循环状态机:流式一轮模型 → 逐字保存 assistant 消息 → 并发执行 tool call、按调用顺序回填 → 再轮,直到某轮不产生 tool call。双计时器(单轮总时长 / 无进展 240s)配合 beginExternalWait 的嵌套暂停,取消与超时分类保持既有语义;重复工具调用 10 次警告、20 次硬停。 - model-client.ts — 直接用 undici 出站,支持 OpenAI 兼容与 Anthropic Messages 两种方言,归一化到同一份 wire 历史;重试只覆盖流开始前的失败。 - deferred-tools.ts / compaction.ts — 延迟工具发现与滚动摘要 checkpoint,格式与旧引擎一致,旧会话历史仍可解析。 - mcp/node-client.ts — 用官方 MCP TypeScript SDK 在进程内直连 stdio / SSE / streamable-HTTP,替掉 gateway HTTP 跳,治理契约(McpInvokeRequest / McpInvokeResponse)不变。 **契约保持不变**:工具实现、权限门、沙箱执行、溯源仍是 packages/agent-runtime 的 createWorkspaceTools 加 API 注入的处理器;SSE AgentEvent 事件面、超时措辞、子 Agent timed_out 判定、finalMessages 交接语义均未变动。因为 assistant 消息逐字保存,provider 怪癖(如 Gemini thought_signature)天然回放,不再需要模型补丁层。 3. **e2e 与文档** - e2e(6 个提交):新增按用户旅程组织的 Playwright 场景与逐步骤报告、网络守卫、journey helper 与 .e2e 装配校验。 - 文档(d2fd2bc):agent-backend.md 按真实模块重写(每节写职责、关键类型/函数、输入输出、失败行为、与权限/工具/溯源的接缝),architecture.md 重画进程图,并同步 control-plane、subagent-orchestration、science-connectors、mcp-tool-protocol、skill-progressive-disclosure、repository-layout、builtin-tools、configuration、web-tools,中英对齐。 **本 PR 未做**(有意保留):web_search / web_fetch 的 provider 执行仍留在 gateway 侧车,仍依赖 vendor 实现,文档已显式标注,未假装已原生化;deer-flow 子模块未删除。 --- **Which issue(s) this PR fixes**: 无对应 issue(架构重构,非缺陷修复)。 --- **Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.)**: 实现与复验由不同角色分别执行,以下为独立复跑结果,并标注各自的被测 commit。 | 范围 | 命令 | 被测 SHA | 结果 | |---|---|---|---| | API 单测全量 | cd services/api && pnpm test | 8efa46f | **429/429 通过,0 失败** | | 原生 loop 定向单测 | node --test dist/native-agent/{native-agent,model-client}.test.js dist/mcp/node-client.test.js | 8efa46f | **21/21 通过** | | 构建与类型检查 | rm -rf services/api/dist && pnpm build | 8efa46f | 通过(含 tsc) | | Gateway Python 套件 | cd services/gateway && python -m unittest discover -s tests | 45afe2b | **137/137 通过**(此后 gateway 代码无改动) | | Gateway smoke | ./test/gateway/run_m0_smoke.sh | 45afe2b | PASS:组装 + 外部工具回调 + 流式 | | Agent loop smoke | ./test/api/run_m1_smoke.sh | 8efa46f | PASS:原生 loop + 流式模型传输 + 真实工具往返 + 多轮历史 | | mocked e2e(隔离栈 4420/4421/4422) | playwright test --config test/playwright.config.ts --grep "@mocked" | 8efa46f | **5 过 / 1 失败 / 1 跳过** | | 文档链接校验 | 全库 Markdown 内部链接扫描 | d2fd2bc | 0 处失效 | **回归判定**:agent 路径已无 vendor 依赖——services/gateway/src 中 deerflow / openjiuwen 仅剩 _engine/web.py 的惰性导入(web provider 专用);services/api/src 中 deerflow / jiuwen / langchain / create_agent **零命中**;POST {gateway}/run 在 Node 侧已无调用方。 **唯一的 e2e 失败是预存产品缺口,非本次回归**:J4(委派子任务旅程)第 5 步断言项目产物目录里应同时出现主 Agent 与子 Agent 的交付物,实际只有 1 份。该用例在 spec 的 preconditions 里就写明「已知缺口 F5,本旅程预期为 FAIL,断言不降级」。已对比基线 0925571(仍走 gateway loop)与 8efa46f(原生 loop)的同一步截图,产物目录内容完全一致,且前 4 步(委派、Subagent 卡片、展开核对过程、主/子职责分离)在原生 loop 下全部通过。 **另有一条与本 PR 无关的基线失败**:packages/agent-runtime 的 runtime.test.ts:146 断言提示词含 [evN]/[aN],而 runtime.ts:213 早已改为 [evidenceN]/[artifactN](由更早的 alias 格式收敛提交造成,断言未同步)。git diff 显示本分支对 packages/ 零改动,且该失败在当前 master 上即可复现,故未在本 PR 内一并修改。 --- **Self-checklist**:(**请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入**) + - [ ] **设计**:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改 + - [x] **测试**:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库 + - [x] **验证**:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述 + - [ ] **接口**:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确 + - [x] **文档**:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓 关于未勾选项的说明: - **设计**:本次重构尚未走 Maintainer 方案评审流程,需要评审后再补勾。 - **接口**:产品对外的 REST / SSE 接口面未变更。变化的是两个内部接缝——gateway POST /run 在 Node 侧已无调用方(路由本身尚未清理),POST /internal/tool-exec 回调随原生化取消(SCIENCE_AGENT_TOOL_CALLBACK_URL 仍被解析但已无人消费)。如需按对外接口口径评审,请指出。 **残留风险**: 1. web_search / web_fetch 的 provider 执行仍在 gateway 侧车,仍依赖 vendor 实现,未原生化。 2. J4 的 F5 缺口描述方向与实测现象相反(spec 写「子 Agent 产物不进目录」,实测缺的是主 Agent 的 results/final.md),建议后续订正,以免误导修复者。 3. gateway POST /run 属死接口,待后续清理。 See merge request: mindspore/ScienceAgent!181 | 1 个月前 | |
chore(npm): 第一方包改名为 sciencediscovery 作用域 仓根包名 science-agent 改为 sciencediscovery,17 个 workspace 包 @science-agent/* 改为 @sciencediscovery/*,同步全部 import、 pnpm --filter 调用、架构检查断言、发布脚本与 pnpm-lock.yaml。 e2e 测试工程 science-agent-e2e 一并改名并更新 CI 缓存根目录。 | 1 个月前 | |
first commit | 1 个月前 | |
first commit | 1 个月前 | |
!181 merge feat/node-native-agent-loop into master refactor: 将 agent 循环原生化到 Node 控制面,退役 gateway 转接层 Created-by: wang_cheng_zhao Commit-by: wang_cheng_zhao Merged-by: wang_cheng_zhao Description: **What type of PR is this?** /kind refactor --- **What does this PR do / why do we need it**: 把 agent 循环从「Node 转交给 Python gateway,由 LangChain create_agent 驱动」改成 **Node 控制面进程内的原生实现**,并把配套的 e2e 用户旅程体系和文档一并补齐。共 10 个提交、99 个文件。 **为什么要做**:原架构下一轮对话要跨两个进程——Node POST {gateway}/run 把 prompt/tools/model/历史发给 Python 侧车,侧车用 LangChain 组环,模型每次调工具再 HTTP 回调 Node 的 /internal/tool-exec。这带来三个长期成本:循环行为受 vendor(deer-flow / LangChain)版本牵制、provider 怪癖要靠额外的模型补丁层兜、以及一条只为传工具结果存在的回调通道和 per-run token 机制。 **改动分三层**: 1. **gateway 内部原生化**(45afe2b) 把 _engine/ 的 agent、model、MCP 接缝在 LangChain 公共 API 上重新实现,保持每个接缝签名与线上契约不变:deferred 工具目录与 tool_search、promotion 状态、摘要与 durable-context、thought_signature 重放、远程内容 tag 净化、基于 langchain-mcp-adapters 的原生 MCP 装载。agent 路径自此不再 import vendor 包。 2. **Node 原生 agent loop**(8efa46f) 新增 services/api/src/native-agent/,删除 gateway-agent.ts(含测试共 1430 行): - index.ts — 循环状态机:流式一轮模型 → 逐字保存 assistant 消息 → 并发执行 tool call、按调用顺序回填 → 再轮,直到某轮不产生 tool call。双计时器(单轮总时长 / 无进展 240s)配合 beginExternalWait 的嵌套暂停,取消与超时分类保持既有语义;重复工具调用 10 次警告、20 次硬停。 - model-client.ts — 直接用 undici 出站,支持 OpenAI 兼容与 Anthropic Messages 两种方言,归一化到同一份 wire 历史;重试只覆盖流开始前的失败。 - deferred-tools.ts / compaction.ts — 延迟工具发现与滚动摘要 checkpoint,格式与旧引擎一致,旧会话历史仍可解析。 - mcp/node-client.ts — 用官方 MCP TypeScript SDK 在进程内直连 stdio / SSE / streamable-HTTP,替掉 gateway HTTP 跳,治理契约(McpInvokeRequest / McpInvokeResponse)不变。 **契约保持不变**:工具实现、权限门、沙箱执行、溯源仍是 packages/agent-runtime 的 createWorkspaceTools 加 API 注入的处理器;SSE AgentEvent 事件面、超时措辞、子 Agent timed_out 判定、finalMessages 交接语义均未变动。因为 assistant 消息逐字保存,provider 怪癖(如 Gemini thought_signature)天然回放,不再需要模型补丁层。 3. **e2e 与文档** - e2e(6 个提交):新增按用户旅程组织的 Playwright 场景与逐步骤报告、网络守卫、journey helper 与 .e2e 装配校验。 - 文档(d2fd2bc):agent-backend.md 按真实模块重写(每节写职责、关键类型/函数、输入输出、失败行为、与权限/工具/溯源的接缝),architecture.md 重画进程图,并同步 control-plane、subagent-orchestration、science-connectors、mcp-tool-protocol、skill-progressive-disclosure、repository-layout、builtin-tools、configuration、web-tools,中英对齐。 **本 PR 未做**(有意保留):web_search / web_fetch 的 provider 执行仍留在 gateway 侧车,仍依赖 vendor 实现,文档已显式标注,未假装已原生化;deer-flow 子模块未删除。 --- **Which issue(s) this PR fixes**: 无对应 issue(架构重构,非缺陷修复)。 --- **Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.)**: 实现与复验由不同角色分别执行,以下为独立复跑结果,并标注各自的被测 commit。 | 范围 | 命令 | 被测 SHA | 结果 | |---|---|---|---| | API 单测全量 | cd services/api && pnpm test | 8efa46f | **429/429 通过,0 失败** | | 原生 loop 定向单测 | node --test dist/native-agent/{native-agent,model-client}.test.js dist/mcp/node-client.test.js | 8efa46f | **21/21 通过** | | 构建与类型检查 | rm -rf services/api/dist && pnpm build | 8efa46f | 通过(含 tsc) | | Gateway Python 套件 | cd services/gateway && python -m unittest discover -s tests | 45afe2b | **137/137 通过**(此后 gateway 代码无改动) | | Gateway smoke | ./test/gateway/run_m0_smoke.sh | 45afe2b | PASS:组装 + 外部工具回调 + 流式 | | Agent loop smoke | ./test/api/run_m1_smoke.sh | 8efa46f | PASS:原生 loop + 流式模型传输 + 真实工具往返 + 多轮历史 | | mocked e2e(隔离栈 4420/4421/4422) | playwright test --config test/playwright.config.ts --grep "@mocked" | 8efa46f | **5 过 / 1 失败 / 1 跳过** | | 文档链接校验 | 全库 Markdown 内部链接扫描 | d2fd2bc | 0 处失效 | **回归判定**:agent 路径已无 vendor 依赖——services/gateway/src 中 deerflow / openjiuwen 仅剩 _engine/web.py 的惰性导入(web provider 专用);services/api/src 中 deerflow / jiuwen / langchain / create_agent **零命中**;POST {gateway}/run 在 Node 侧已无调用方。 **唯一的 e2e 失败是预存产品缺口,非本次回归**:J4(委派子任务旅程)第 5 步断言项目产物目录里应同时出现主 Agent 与子 Agent 的交付物,实际只有 1 份。该用例在 spec 的 preconditions 里就写明「已知缺口 F5,本旅程预期为 FAIL,断言不降级」。已对比基线 0925571(仍走 gateway loop)与 8efa46f(原生 loop)的同一步截图,产物目录内容完全一致,且前 4 步(委派、Subagent 卡片、展开核对过程、主/子职责分离)在原生 loop 下全部通过。 **另有一条与本 PR 无关的基线失败**:packages/agent-runtime 的 runtime.test.ts:146 断言提示词含 [evN]/[aN],而 runtime.ts:213 早已改为 [evidenceN]/[artifactN](由更早的 alias 格式收敛提交造成,断言未同步)。git diff 显示本分支对 packages/ 零改动,且该失败在当前 master 上即可复现,故未在本 PR 内一并修改。 --- **Self-checklist**:(**请自检,在[ ]内打上x,我们将检视你的完成情况,否则会导致pr无法合入**) + - [ ] **设计**:PR对应的方案是否已经经过Maintainer评审,方案检视意见是否均已答复并完成方案修改 + - [x] **测试**:PR中的代码是否已有UT/ST测试用例进行充分的覆盖,新增测试用例是否随本PR一并上库或已经上库 + - [x] **验证**:PR描述信息中是否已包含对该PR对应的Feature、Refactor、Bugfix的预期目标达成情况的详细验证结果描述 + - [ ] **接口**:是否涉及对外接口变更,相应变更已得到接口评审组织的通过,API对应的注释信息已经刷新正确 + - [x] **文档**:是否涉及官网文档修改,如果涉及请及时提交资料到Doc仓 关于未勾选项的说明: - **设计**:本次重构尚未走 Maintainer 方案评审流程,需要评审后再补勾。 - **接口**:产品对外的 REST / SSE 接口面未变更。变化的是两个内部接缝——gateway POST /run 在 Node 侧已无调用方(路由本身尚未清理),POST /internal/tool-exec 回调随原生化取消(SCIENCE_AGENT_TOOL_CALLBACK_URL 仍被解析但已无人消费)。如需按对外接口口径评审,请指出。 **残留风险**: 1. web_search / web_fetch 的 provider 执行仍在 gateway 侧车,仍依赖 vendor 实现,未原生化。 2. J4 的 F5 缺口描述方向与实测现象相反(spec 写「子 Agent 产物不进目录」,实测缺的是主 Agent 的 results/final.md),建议后续订正,以免误导修复者。 3. gateway POST /run 属死接口,待后续清理。 See merge request: mindspore/ScienceAgent!181 | 1 个月前 | |
first commit | 1 个月前 | |
test(e2e): synchronize mocked journeys with what the workbench renders Three mocked specs waited for something the product does not do, and none of them had ever run on a pipeline: CodeArts does not run the browser E2E layer, and on the GitHub mirror the layer aborted at check-e2e-meta before starting a journey. journey-reviewer-auto-audit asserted .reviewer-control-card was visible as soon as the Session opened. The card is rendered inside a collapsed details.workspace-fold, like the Agent-activity and Evolve folds beside it, so Playwright found the element 24 times and reported it hidden every time. The step now opens the disclosure first, the way a user reads those controls, and then asserts the card. timeouts-runtime-status waited for networkidle after page.goto("/"). When the workbench restores a Session it starts five per-Session pollers — agent-activity and four mcp/* endpoints, about 30 requests each over the window — so the browser never goes 500 ms without a request and the wait consumed the whole 60 s budget. The trace ends in page.waitForLoadState: Test timeout of 60000ms exceeded, at timeouts-runtime-status.spec.ts:108. It now waits for the shell it is about to click in. Whether a Session is restored depends on what ran before, which is why the spec looked stable. literature-review's openWorkspace carried the same networkidle call as a redundant prefix to an already-correct visible assertion. It passed this round only because no Session had been restored in its context; removing the call leaves the assertion as the wait. Verified: node test/check-e2e-meta.mjs 42 spec file(s), 0 error(s), 11 legacy warning(s) — unchanged. | 14 天前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 16 天前 | ||
| 22 天前 | ||
| 14 天前 | ||
| 22 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 13 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 28 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 21 天前 | ||
| 13 天前 | ||
| 13 天前 | ||
| 19 天前 | ||
| 17 天前 | ||
| 19 天前 | ||
| 15 天前 | ||
| 17 天前 | ||
| 11 天前 | ||
| 11 天前 | ||
| 17 天前 | ||
| 13 天前 | ||
| 17 天前 | ||
| 17 天前 | ||
| 18 天前 | ||
| 11 天前 | ||
| 18 天前 | ||
| 19 天前 | ||
| 16 天前 | ||
| 18 天前 | ||
| 11 天前 | ||
| 1 个月前 | ||
| 19 天前 | ||
| 14 天前 | ||
| 14 天前 | ||
| 14 天前 | ||
| 18 天前 | ||
| 22 天前 | ||
| 14 天前 | ||
| 18 天前 | ||
| 14 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 14 天前 |