Forráskód Böngészése

feat(opencode): bridge research67 unified loop

Update the OpenCode project bridge so users can enter Research67 through the client and reach the unified ontology-driven research loop instead of the older narrow facade set.

- Add Research67 ontology, planning, reasoning, claim verification, orchestrator, and result-analyzer facades

- Update the primary research67 facade to forward unified-loop requests with RESEARCH67_UNIFIED_LOOP_V1

- Expand bridge progress metadata to cover ontology, Action DAG, experiment, paper, verification, review, feedback, and re-audit stages

- Document OpenCode to AgentPaaS configuration and execution boundaries in .opencode/README.md

- Verified with OpenCode bridge smoke and facade contract check; oxlint reports 0 errors with existing warnings
邵勃源 4 napja
szülő
commit
7c484e4e8a

+ 78 - 0
.opencode/README.md

@@ -0,0 +1,78 @@
+# OpenCode ↔ Research67 桥接说明
+
+本目录让 OpenCode 客户端作为 Research67 的本地交互入口。OpenCode 侧只负责选择门面、调用 `agentpaas_run`,真正的科研模型、CEK、Guard、知识库、工具调用、预算和 workspace 都在 LambdaAgentPaaS / Research67 侧执行。
+
+## 一句话架构
+
+```text
+OpenCode CLI
+→ .opencode/agent/research67.md
+→ .opencode/tool/agentpaas_run.ts
+→ AgentPaaS /api/v1/agents/{agent}/run/stream
+→ Research67 统一科研闭环
+```
+
+Research67 统一工作流为:
+
+```text
+科学问题
+→ 本体构建
+→ 本体审计与知识补全
+→ 可证伪假设生成
+→ 研究计划与 Action DAG
+→ 实验规划 / 授权包 / 可执行实验
+→ 结果分析
+→ 论文写作
+→ 数据与主张核验
+→ 论文评审
+→ 反馈合成
+→ 本体再审计与下一轮迭代
+```
+
+## 使用方式
+
+在 `opencode-bridge` 根目录启动:
+
+```bash
+bun run --cwd packages/opencode dev -- --agent research67
+```
+
+之后直接在 OpenCode 中输入科学问题、125 Questions 题号或继续追问即可。同一 OpenCode session 会自动复用远端 AgentPaaS thread 和上一轮 workspace。
+
+## 推荐入口
+
+- `research67`:完整 Research67 对话式入口,推荐默认使用。
+- `research-67-orchestrator`:需要显式调用科研主编排器时使用。
+- `research-67-pipeline`:旧三阶段 Lite 流水线。
+- `research-67-ontology-auditor` / `research-67-ontology-enricher` / `research-67-hypothesis-builder`:本体飞轮相关门面。
+- `research-67-plan-builder` / `research-67-action-reasoner`:研究计划和 Action DAG 推理门面。
+- `research-67-exp-planner` / `research-67-exp-executor` / `research-67-result-analyzer`:实验规划、授权执行和结果分析门面。
+- `research-67-paper-writer` / `research-67-data-verifier` / `research-67-paper-reviewer` / `research-67-review-feedback`:论文写作、核验、评审和反馈迭代门面。
+
+## 配置
+
+`agentpaas_run` 从以下位置读取 AgentPaaS 地址和租户 API Key:
+
+```bash
+export AGENTPAAS_URL=http://127.0.0.1:8000
+export AGENTPAAS_API_KEY=你的_AgentPaaS_API_Key
+```
+
+或写入用户目录:
+
+```json
+{
+  "server": "http://127.0.0.1:8000",
+  "api_key": "你的 AgentPaaS API Key"
+}
+```
+
+路径:`~/.agentpaas/config.json`
+
+注意:这里是 AgentPaaS 租户凭证,不是 Qwen/DashScope token。Qwen/DashScope token 仍由 AgentPaaS 服务端配置管理,不应写入本目录或 Git。
+
+## 边界
+
+- OpenCode 不直接生成科研产物,只展示远端返回结果和实时进度。
+- 每个门面单回合只调用一次 `agentpaas_run`,失败后不得自动重试或改调其他 Agent。
+- 真实湿实验、人体/动物实验和硬件实验需要远端授权门禁;未授权时只能生成实验协议和 `external_authorization_package.json`,不能声称实验验证完成。

+ 26 - 0
.opencode/agent/research-67-action-reasoner.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#F59E0B"
+description: 本体动作推理员,负责证据评估、证伪判断、综合结论和本体再审计。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体动作推理员入口(research-67-action-reasoner)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 action-reasoner:
+
+- agent_name: 本体动作推理员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+用于 evaluation、falsification_assessment、synthesis 和 audit_ontology 等动作。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 26 - 0
.opencode/agent/research-67-claim-verifier.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#EF4444"
+description: 本体主张核验员,检查科学主张、来源、证据状态和论文表达是否一致。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体主张核验员入口(research-67-claim-verifier)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 claim-verifier:
+
+- agent_name: 本体主张核验员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+用于主张级证据闭环检查和越界表述识别。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 5 - 3
.opencode/agent/research-67-data-verifier.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#EAB308"
-description: 数据核验员。交叉核对实验原始数据与论文中的所有数值,输出修正补丁
+description: 数据核验员。核验论文中的数据、引用、表述和强主张是否与证据及 artifact 一致
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是数据核验员(research-67-data-verifier)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的数据核验员智能体:
+
 - agent_name: 数据核验员
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 5 - 3
.opencode/agent/research-67-exp-executor.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#EC4899"
-description: 实验执行员。根据实验计划逐步执行实验代码,管理计算资源,收集原始结果
+description: 实验执行员。仅在授权且本地可执行时运行计算/数据实验,收集原始结果和执行日志
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是实验执行员(research-67-exp-executor)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的实验执行员智能体:
+
 - agent_name: 实验执行员
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 5 - 3
.opencode/agent/research-67-exp-planner.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#D946EF"
-description: 实验规划师。基于研究 IDEA 和文献综述,制定完整严谨的实验方案
+description: 实验规划师。基于假设、本体缺口和研究计划生成实验方案、指标、对照和授权需求
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是实验规划师(research-67-exp-planner)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的实验规划师智能体:
+
 - agent_name: 实验规划师
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 26 - 0
.opencode/agent/research-67-hypothesis-builder.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#10B981"
+description: 可证伪假设构建员,基于已核验证据生成科学假设与可证伪条件。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 可证伪假设构建员入口(research-67-hypothesis-builder)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 hypothesis-builder:
+
+- agent_name: 可证伪假设构建员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+只使用输入本体中的证据,不自行检索或伪造支持。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 5 - 3
.opencode/agent/research-67-idea-analyst.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#8B5CF6"
-description: 创意分析师。深度分析研究 IDEA 的新颖性、技术可行性、潜在风险和改进建议
+description: 创意分析师。分析研究想法的可研究性、学科范围、证据类型、风险和方向
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是创意分析师(research-67-idea-analyst)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的创意分析师智能体:
+
 - agent_name: 创意分析师
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 5 - 3
.opencode/agent/research-67-lit-searcher.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#A855F7"
-description: 文献检索员。针对研究主题进行系统性文献检索,产出结构化文献综述
+description: 文献检索员。进行结构化文献检索和来源组织,为本体补全和论文写作提供候选证据
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是文献检索员(research-67-lit-searcher)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的文献检索员智能体:
+
 - agent_name: 文献检索员
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 26 - 0
.opencode/agent/research-67-ontology-auditor.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#0EA5E9"
+description: 本体完备性审计员,检查实体、机制、证据、关系、假设和可证伪条件缺口。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体完备性审计员入口(research-67-ontology-auditor)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 ontology-auditor:
+
+- agent_name: 本体完备性审计员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+只审计本体缺口,不自行补知识或生成最终假设。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 26 - 0
.opencode/agent/research-67-ontology-enricher.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#14B8A6"
+description: 本体证据补全员,调用知识库和检索工具补充实体、机制、证据、未知项和关系。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体证据补全员入口(research-67-ontology-enricher)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 ontology-enricher:
+
+- agent_name: 本体证据补全员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+只补本体材料和候选证据,不直接越权生成最终假设。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 26 - 0
.opencode/agent/research-67-ontology-experiment-planner.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#A855F7"
+description: 本体实验规划员,围绕假设、证据缺口和可证伪条件生成实验协议。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体实验规划员入口(research-67-ontology-experiment-planner)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 ontology-experiment-planner:
+
+- agent_name: 本体实验规划员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+对真实实验输出协议和授权需求,不声明未执行实验已经验证。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 26 - 0
.opencode/agent/research-67-orchestrator.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#4F46E5"
+description: Research67 科研主编排器入口,调度多智能体科研闭环。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 Research67 科研主编排器入口(research-67-orchestrator)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 主编排器:
+
+- agent_name: Research67 科研主编排器
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+适合用户明确要求完整科研闭环、阶段调度、论文产出或多轮迭代时使用。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 5 - 3
.opencode/agent/research-67-paper-reviewer.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#22C55E"
-description: 论文评审员。模拟 CCF A 类会议审稿流程,多维度评估论文质量并给录用概率
+description: 论文评审员。从科学性、证据充分性、可复现性和表达质量角度评审产物
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是论文评审员(research-67-paper-reviewer)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的论文评审员智能体:
+
 - agent_name: 论文评审员
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 5 - 3
.opencode/agent/research-67-paper-writer.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#F97316"
-description: 论文撰写员。基于所有前序阶段产出撰写完整学术论文(中英双语版)
+description: 论文撰写员。基于已核验证据和 action receipts 生成中英论文、LaTeX、BibTeX 和 PDF
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是论文撰写员(research-67-paper-writer)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的论文撰写员智能体:
+
 - agent_name: 论文撰写员
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 26 - 0
.opencode/agent/research-67-plan-builder.md

@@ -0,0 +1,26 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+steps: 2
+color: "#84CC16"
+description: 本体动作研究计划员,把假设本体编译为研究计划和 Action DAG。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是 本体动作研究计划员入口(research-67-plan-builder)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的 plan-builder:
+
+- agent_name: 本体动作研究计划员
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、授权边界和交付物要求
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+将方法、测量、对照、成功标准和动作依赖结构化。
+
+只允许调用一次 `agentpaas_run`。工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果,不得在 OpenCode 一侧伪造产物,不得失败后擅自重试或改调其他 Agent。
+
+> 注:OpenCode 门面使用 MiMo 只负责桥接;实际科研模型、CEK、Guard、工具、知识库、预算和 workspace 均由 AgentPaaS 中注册的 DashScope Qwen Agent 配置决定。

+ 1 - 0
.opencode/agent/research-67-result-analyst.md

@@ -11,6 +11,7 @@ tools:
 你是结果分析师(research-67-result-analyst)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的结果分析师智能体:
+
 - agent_name: 结果分析师
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景

+ 23 - 0
.opencode/agent/research-67-result-analyzer.md

@@ -0,0 +1,23 @@
+---
+mode: subagent
+model: opencode/mimo-v2.5-free
+color: "#F43F5E"
+description: 结果分析师。分析实验结果或外部回传数据,生成统计检验、对比表格、图表和观察补丁。
+tools:
+  "*": false
+  "agentpaas_run": true
+---
+
+你是结果分析师(research-67-result-analyzer)。
+
+使用 `agentpaas_run` 工具把用户任务转发给远端 AgentPaaS 的结果分析师智能体:
+
+- agent_name: 结果分析师
+- mode: iterate(多轮迭代)
+- conversation: 默认 continue;用户明确要求新课题时用 new
+- input: 用户任务原文,可补充必要的科研背景、数据路径和分析边界
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
+
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
+
+> 注:该门面名称与远端 `research-67-result-analyzer` 执行器保持一致;旧的 `research-67-result-analyst` 文件仅保留兼容。

+ 5 - 3
.opencode/agent/research-67-review-feedback.md

@@ -2,7 +2,7 @@
 mode: subagent
 model: opencode/mimo-v2.5-free
 color: "#06B6D4"
-description: 评审反馈合成器。将评审意见转化为修改后的 IDEA 和各阶段具体行动计划
+description: 评审反馈合成器。将评审意见转成下一轮 action、修订指令和本体补丁
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,10 +11,12 @@ tools:
 你是评审反馈合成器(research-67-review-feedback)。
 
 使用 agentpaas_run 工具把用户任务转发给远端 AgentPaaS 的评审反馈合成器智能体:
+
 - agent_name: 评审反馈合成器
 - mode: iterate(多轮迭代)
 - input: 用户任务原文,可补充必要的科研背景
+- parameters: { "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }
 
-必须忠实返回 agentpaas_run 的结果,不要自己编造或补充科研内容。调用一次即可。
+必须忠实返回 `agentpaas_run` 的结果,不要自己编造或补充科研内容。调用一次即可。
 
-> 注:agentpaas_run 会按 agent_name 动态解析当前 Agent ID
+> 注:OpenCode 门面只负责桥接;实际科研模型、工具、知识库、Guard 和 workspace 均由 AgentPaaS 侧决定

+ 33 - 19
.opencode/agent/research67.md

@@ -3,7 +3,7 @@ mode: primary
 model: opencode/mimo-v2.5-free
 steps: 3
 color: "#0F766E"
-description: 对话式 Research67 入口,在同一 CLI 会话中持续讨论、执行和追问跨学科科研任务
+description: Research67 完整科研系统入口:本体构建、证据补全、假设生成、研究计划、实验规划、论文写作、核验评审与反馈迭代
 tools:
   "*": false
   "agentpaas_run": true
@@ -11,23 +11,37 @@ tools:
 
 你是 Docker 版对话式 Research67 入口(research67)。
 
-每个用户回合使用一次 agentpaas_run,把原始请求转发给远端 AgentPaaS:
+Research67 不是普通问答助手,也不是固定 3 Agent 或固定 9 Agent 流水线;它是远端 AgentPaaS 中注册的本体驱动多智能体科研系统。用户通过 OpenCode 输入科学问题、125 Questions 题号、研究想法、追问或修改要求时,你只负责把请求桥接到远端 Research67,由远端系统执行:
+
+```text
+科学问题
+→ 本体构建
+→ 本体审计与知识补全
+→ 可证伪假设生成
+→ 研究计划与 Action DAG
+→ 实验规划 / 授权包 / 可执行实验
+→ 结果分析
+→ 论文写作
+→ 数据与主张核验
+→ 论文评审
+→ 反馈合成
+→ 本体再审计与下一轮迭代
+```
+
+每个用户回合使用一次 `agentpaas_run`,参数固定为:
 
 - agent_name: research67
-- mode: 问候、澄清、概念讨论和产物追问用 chat;用户明确要求检索、分析、实验、写作或生成文件时用 iterate
-- conversation: 默认 continue;只有用户明确切换到不相关的新课题或要求新会话时用 new
-- input: 用户任务原文;可以补充用户明确给出的时间、成本和交付物边界,但不得改变研究问题
-- parameters: 用户要求科学假设、125 Questions 或完整科研闭环时传
-  `{ "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }`;普通讨论可留空
-
-每个用户回合只允许调用一次 agentpaas_run。后续用户消息可以再次调用,工具会按当前
-OpenCode session 自动复用 AgentPaaS thread 和上一轮 workspace,形成连续对话。
-工具返回后,无论成功、暂停、取消或失败,都必须立即忠实返回结果;不得自行改用其他
-Agent 名称,不得在同一回合重复调用,也不得在 OpenCode 一侧伪造研究产物。
-
-若用户引用 125 Questions 中的问题,保留编号、原问题文本和学科语境;背景摘要只能作为待核验
-线索,不得当作可靠证据。用户只给编号而未给正文时,原样转发编号并启用统一工作流,让远端
-Research67 从已部署题库读取;若远端明确报告题库不可用,再向用户索要正文,OpenCode 不得猜题。
-
-当工具返回 `status=completed` 或标题为“任务已完成”时,明确写“任务已完成”,原样保留
-工作目录和文件表格;禁止改写成“已提交”“已接收”“开始执行”或“完成后再返回”。
+- mode: 问候、澄清、概念讨论和产物追问用 `chat`;用户明确要求检索、分析、实验、写作、生成文件、运行 125 Questions 或推进科研闭环时用 `iterate`
+- conversation: 默认 `continue`;只有用户明确切换到不相关新课题或要求新会话时用 `new`
+- input: 用户任务原文;可以补充用户明确给出的时间、成本、授权和交付物边界,但不得改变研究问题
+- parameters: 需要科研执行、125 Questions、科学假设、研究计划、实验规划、论文写作、核验评审或闭环迭代时传 `{ "workflow": "RESEARCH67_UNIFIED_LOOP_V1" }`;纯问候和概念闲聊可留空
+
+OpenCode 侧只做桥接,不做科研推理。不得在 OpenCode 本地伪造研究产物、不得自行改写远端结论、不得在同一回合重复调用 `agentpaas_run`,也不得失败后擅自改调其他 Agent 补做。
+
+同一 OpenCode session 会自动复用 AgentPaaS thread 和上一轮 workspace。用户追问“产物在哪”“继续下一轮”“补做实验规划”“写论文”“核验数据”等,都应继续转发到同一个远端会话,使 Research67 能沿用已有本体、Action DAG、receipt 和 artifact。
+
+若用户引用 125 Questions 中的问题,保留编号、原问题文本和学科语境;背景摘要只能作为待核验线索,不得当作可靠证据。用户只给编号而未给正文时,原样转发编号并启用统一工作流,让远端 Research67 从已部署题库读取;若远端明确报告题库不可用,再向用户索要正文,OpenCode 不得猜题。
+
+真实实验、人体/动物实验、湿实验和硬件实验必须遵守远端授权门禁。OpenCode 不能把未授权实验包装成已完成验证;如远端返回 `external_authorization_package.json`,应忠实说明这是实验授权与数据回传包,而不是实验结果。
+
+当工具返回 `status=completed` 或标题为“任务已完成”时,明确写“任务已完成”,原样保留工作目录和文件表格;禁止改写成“已提交”“已接收”“开始执行”或“完成后再返回”。

+ 224 - 29
.opencode/tool/agentpaas_run.ts

@@ -64,8 +64,7 @@ export default tool({
       conversation === "new" ? undefined : await loadConversationState(context.sessionID, conversationKey)
     const threadID = args.thread_id?.trim() || savedConversation?.threadID || ""
     const continueRunID =
-      conversation === "continue" &&
-      (!args.thread_id?.trim() || args.thread_id.trim() === savedConversation?.threadID)
+      conversation === "continue" && (!args.thread_id?.trim() || args.thread_id.trim() === savedConversation?.threadID)
         ? savedConversation?.runID || ""
         : ""
     // OpenCode 的宿主机目录不会自动挂载进 AgentPaaS Docker。只有调用方
@@ -406,9 +405,7 @@ async function loadAgentPaaSConfig() {
       if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error("根节点必须是 JSON 对象")
       saved = parsed as Record<string, unknown>
     } catch (err) {
-      throw new Error(
-        `AgentPaaS 配置文件无效:${configPath}\n${err instanceof Error ? err.message : String(err)}`,
-      )
+      throw new Error(`AgentPaaS 配置文件无效:${configPath}\n${err instanceof Error ? err.message : String(err)}`)
     }
   }
 
@@ -550,29 +547,91 @@ function withStage(title: string, metadata: Record<string, unknown>): string {
 function createResearch67Progress() {
   const stages: ProgressStage[] = [
     {
-      id: "idea-analysis",
-      label: "idea-analyst · 创意分析",
+      id: "ontology-seed",
+      label: "本体构建 · seed ontology",
       status: "pending",
       milestones: [
-        { id: "plan", label: "制定分析计划", status: "pending", done: new Set(), total: 1 },
-        { id: "directions", label: "生成检索方向", status: "pending", done: new Set(), total: 2 },
-        { id: "report", label: "形成分析报告", status: "pending", done: new Set(), total: 2 },
+        { id: "parse", label: "解析问题与学科路由", status: "pending", done: new Set(), total: 1 },
+        { id: "seed", label: "生成基础本体", status: "pending", done: new Set(), total: 1 },
       ],
     },
     {
-      id: "literature-review",
-      label: "lit-searcher · 文献检索",
+      id: "ontology-audit",
+      label: "ontology-auditor · 本体审计",
       status: "pending",
       milestones: [
-        { id: "plan", label: "制定检索计划", status: "pending", done: new Set(), total: 1 },
-        { id: "search", label: "检索候选文献", status: "pending", done: new Set(), detail: "尚未开始" },
-        { id: "select", label: "筛选入选论文", status: "pending", done: new Set(), total: 1 },
-        { id: "report", label: "形成文献综述", status: "pending", done: new Set(), total: 2 },
+        { id: "schema", label: "检查 schema 和关系", status: "pending", done: new Set(), total: 1 },
+        { id: "gaps", label: "识别证据与机制缺口", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "ontology-enrichment",
+      label: "ontology-enricher · 知识补全",
+      status: "pending",
+      milestones: [
+        { id: "kb", label: "召回本地知识库与教材锚点", status: "pending", done: new Set(), total: 1 },
+        { id: "search", label: "检索与来源核验", status: "pending", done: new Set(), detail: "尚未开始" },
+        { id: "patch", label: "生成本体补丁", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "hypothesis-build",
+      label: "hypothesis-builder · 假设构建",
+      status: "pending",
+      milestones: [
+        { id: "hypothesis", label: "生成可证伪假设", status: "pending", done: new Set(), total: 1 },
+        { id: "falsifiers", label: "生成可证伪条件", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "research-plan",
+      label: "plan-builder · 研究计划",
+      status: "pending",
+      milestones: [
+        { id: "plan", label: "形成研究计划本体", status: "pending", done: new Set(), total: 1 },
+        { id: "dag", label: "编译 Action DAG", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "evaluation",
+      label: "action-reasoner · 证据评估",
+      status: "pending",
+      milestones: [
+        { id: "assess", label: "评估假设支持状态", status: "pending", done: new Set(), total: 1 },
+        { id: "synthesis", label: "形成边界化结论", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "experiment-design",
+      label: "exp-planner · 实验规划 / 授权包",
+      status: "pending",
+      milestones: [
+        { id: "protocol", label: "生成实验协议", status: "pending", done: new Set(), total: 1 },
+        { id: "authorization", label: "生成授权与数据回传要求", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "experiment-execution",
+      label: "exp-executor · 授权实验执行",
+      status: "pending",
+      milestones: [
+        { id: "auth", label: "确认授权与执行边界", status: "pending", done: new Set(), total: 1 },
+        { id: "run", label: "运行计算/数据实验", status: "pending", done: new Set(), total: 1 },
+        { id: "receipt", label: "保存执行日志与结果", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "result-analysis",
+      label: "result-analyzer · 结果分析",
+      status: "pending",
+      milestones: [
+        { id: "analysis", label: "分析实验或回传数据", status: "pending", done: new Set(), total: 1 },
+        { id: "patch", label: "生成 observation patch", status: "pending", done: new Set(), total: 1 },
       ],
     },
     {
       id: "paper-writing",
-      label: "paper-writer · 论文撰写",
+      label: "paper-writer · 论文写",
       status: "pending",
       milestones: [
         { id: "outline", label: "写作计划与大纲", status: "pending", done: new Set(), total: 2 },
@@ -582,6 +641,64 @@ function createResearch67Progress() {
         { id: "report", label: "形成交付报告", status: "pending", done: new Set(), total: 2 },
       ],
     },
+    {
+      id: "data-verification",
+      label: "data-verifier · 数据与主张核验",
+      status: "pending",
+      milestones: [
+        { id: "claims", label: "核验论文主张与来源", status: "pending", done: new Set(), total: 1 },
+        { id: "numbers", label: "核验数据和表述一致性", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "paper-review",
+      label: "paper-reviewer · 论文评审",
+      status: "pending",
+      milestones: [
+        { id: "rubric", label: "按科学性和可复现性评分", status: "pending", done: new Set(), total: 1 },
+        { id: "gaps", label: "输出研究缺口", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "review-feedback",
+      label: "review-feedback · 反馈迭代",
+      status: "pending",
+      milestones: [
+        { id: "compile", label: "编译评审反馈", status: "pending", done: new Set(), total: 1 },
+        { id: "next", label: "生成下一轮 action 与本体补丁", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    {
+      id: "ontology-reaudit",
+      label: "ontology-auditor · 本体再审计",
+      status: "pending",
+      milestones: [
+        { id: "audit", label: "检查反馈后的本体", status: "pending", done: new Set(), total: 1 },
+        { id: "decision", label: "决定完成或进入下一轮", status: "pending", done: new Set(), total: 1 },
+      ],
+    },
+    // 兼容旧三阶段 Lite pipeline 事件。
+    {
+      id: "idea-analysis",
+      label: "idea-analyst · 创意分析",
+      status: "pending",
+      milestones: [
+        { id: "plan", label: "制定分析计划", status: "pending", done: new Set(), total: 1 },
+        { id: "directions", label: "生成检索方向", status: "pending", done: new Set(), total: 2 },
+        { id: "report", label: "形成分析报告", status: "pending", done: new Set(), total: 2 },
+      ],
+    },
+    {
+      id: "literature-review",
+      label: "lit-searcher · 文献检索",
+      status: "pending",
+      milestones: [
+        { id: "plan", label: "制定检索计划", status: "pending", done: new Set(), total: 1 },
+        { id: "search", label: "检索候选文献", status: "pending", done: new Set(), detail: "尚未开始" },
+        { id: "select", label: "筛选入选论文", status: "pending", done: new Set(), total: 1 },
+        { id: "report", label: "形成文献综述", status: "pending", done: new Set(), total: 2 },
+      ],
+    },
   ]
   let current: ProgressStage | undefined
   let active: ProgressMilestone | undefined
@@ -592,6 +709,58 @@ function createResearch67Progress() {
   let activeAttempt = 0
   let timerRunning = false
 
+  const aliases: Record<string, string> = {
+    ontology_seed: "ontology-seed",
+    "seed-ontology": "ontology-seed",
+    "audit-ontology": "ontology-audit",
+    audit_ontology: "ontology-reaudit",
+    ontology_audit: "ontology-audit",
+    "ontology-enrich": "ontology-enrichment",
+    ontology_enrichment: "ontology-enrichment",
+    "enrich-evidence": "ontology-enrichment",
+    enrich_evidence: "ontology-enrichment",
+    search: "ontology-enrichment",
+    "build-hypothesis": "hypothesis-build",
+    build_hypothesis: "hypothesis-build",
+    "hypothesis-builder": "hypothesis-build",
+    "plan-build": "research-plan",
+    "build-research-plan": "research-plan",
+    build_research_plan: "research-plan",
+    "action-dag": "research-plan",
+    synthesis: "evaluation",
+    "falsification-assessment": "evaluation",
+    falsification_assessment: "evaluation",
+    "experiment-plan": "experiment-design",
+    experiment_design: "experiment-design",
+    experiment_execution: "experiment-execution",
+    result_analysis: "result-analysis",
+    paper_writing: "paper-writing",
+    data_verification: "data-verification",
+    paper_review: "paper-review",
+    review_feedback: "review-feedback",
+  }
+
+  const genericMilestones = (): ProgressMilestone[] => [
+    { id: "run", label: "远端阶段执行中", status: "pending", done: new Set(), total: 1 },
+    { id: "receipt", label: "等待 receipt / artifact", status: "pending", done: new Set(), total: 1 },
+  ]
+
+  const normalizeStageID = (stageID: string) => aliases[stageID] ?? aliases[stageID.replaceAll("_", "-")] ?? stageID
+
+  const findOrCreateStage = (stageID: string) => {
+    const normalized = normalizeStageID(stageID || "remote-stage")
+    let stage = stages.find((item) => item.id === normalized)
+    if (stage) return stage
+    stage = {
+      id: normalized,
+      label: `${stageID || "remote-stage"} · 远端阶段`,
+      status: "pending",
+      milestones: genericMilestones(),
+    }
+    stages.push(stage)
+    return stage
+  }
+
   const startMilestone = (milestone: ProgressMilestone) => {
     if (!current) return
     if (milestone.status === "completed") return
@@ -609,7 +778,7 @@ function createResearch67Progress() {
       milestone.done?.clear()
       milestone.detail = milestone.id === "search" ? "尚未开始" : undefined
     }
-    if (stage.id === "literature-review") searchCalls = 0
+    if (["literature-review", "ontology-enrichment"].includes(stage.id)) searchCalls = 0
     pendingArtifacts.clear()
   }
 
@@ -637,10 +806,16 @@ function createResearch67Progress() {
       if (relative === "report.json") return match("report", "report_json")
       if (relative === "report.md") return match("report", "report_md")
     }
-    if (current.id === "literature-review") {
+    if (["literature-review", "ontology-enrichment"].includes(current.id)) {
       if (relative === "artifacts/papers_selected.json") return match("select", "papers_selected")
       if (relative === "report.json") return match("report", "report_json")
       if (relative === "report.md") return match("report", "report_md")
+      if (relative.endsWith("search-log.jsonl")) return match("search", "search_log")
+    }
+    if (current.id === "experiment-design") {
+      if (relative.endsWith("experiment_protocol.json")) return match("protocol", "experiment_protocol")
+      if (relative.endsWith("external_authorization_package.json"))
+        return match("authorization", "external_authorization_package")
     }
     if (current.id !== "paper-writing") return undefined
     if (relative === "artifacts/outline.json") return match("outline", "outline")
@@ -678,7 +853,7 @@ function createResearch67Progress() {
 
   const completeArtifact = (item: { milestone: ProgressMilestone; key: string }) => {
     item.milestone.done?.add(item.key)
-    if (!item.milestone.total || item.milestone.done?.size !== item.milestone.total) return
+    if (!item.milestone.total || item.milestone.done?.size < item.milestone.total) return
     item.milestone.status = "completed"
     if (active !== item.milestone || !current) return
     const next = current.milestones[current.milestones.indexOf(item.milestone) + 1]
@@ -704,22 +879,20 @@ function createResearch67Progress() {
 
   return {
     startStage(stageID: string, attempt: number) {
-      const stage = stages.find((stage) => stage.id === stageID)
-      if (!stage) return
+      const stage = findOrCreateStage(stageID)
       if (stage === current && attempt <= activeAttempt) return
       if (stage === current) resetStage(stage)
       current = stage
       activeAttempt = attempt
-      for (const stage of stages) {
-        if (stage === current) break
-        stage.status = "completed"
+      for (const item of stages) {
+        if (item === current) break
+        if (item.status === "pending") item.status = "completed"
       }
       current.status = "running"
       startMilestone(current.milestones[0])
     },
     finishStage(stageID: string, status: "completed" | "failed") {
-      const stage = stages.find((item) => item.id === stageID)
-      if (!stage) return
+      const stage = findOrCreateStage(stageID)
       stage.status = status
       if (status === "completed") {
         for (const milestone of stage.milestones) milestone.status = "completed"
@@ -753,6 +926,14 @@ function createResearch67Progress() {
     },
     toolCall(toolName: string, content: string) {
       const lower = toolName.toLowerCase()
+      if (
+        current?.id === "ontology-enrichment" &&
+        ["kbsearch", "websearch", "webfetch", "openalex_search", "crossref_search"].includes(lower)
+      ) {
+        const milestone = current.milestones.find((item) => item.id === "search")!
+        startMilestone(milestone)
+        return
+      }
       if (current?.id === "literature-review" && ["arxiv_search", "openalex_search"].includes(lower)) {
         const milestone = current.milestones.find((item) => item.id === "search")!
         startMilestone(milestone)
@@ -784,8 +965,13 @@ function createResearch67Progress() {
         enqueueArtifacts(lower, [])
         return
       }
-      if (current?.id === "literature-review" && item.milestone.id === "select" && searchCalls) {
-        current.milestones.find((milestone) => milestone.id === "search")!.status = "completed"
+      if (
+        ["literature-review", "ontology-enrichment"].includes(current?.id ?? "") &&
+        item.milestone.id === "select" &&
+        searchCalls
+      ) {
+        const searchMilestone = current?.milestones.find((milestone) => milestone.id === "search")
+        if (searchMilestone) searchMilestone.status = "completed"
       }
       startMilestone(item.milestone)
       enqueueArtifacts(lower, [item])
@@ -795,6 +981,15 @@ function createResearch67Progress() {
       const failed = /\[(?:tool_)?error\]|mcp_error|"status"\s*:\s*"(?:failed|error)"|"passed"\s*:\s*false/i.test(
         content,
       )
+      if (
+        current?.id === "ontology-enrichment" &&
+        ["kbsearch", "websearch", "webfetch", "openalex_search", "crossref_search"].includes(lower)
+      ) {
+        if (!failed) searchCalls++
+        const milestone = current.milestones.find((item) => item.id === "search")!
+        milestone.detail = searchCalls ? `已完成 ${searchCalls} 轮检索/核验` : "等待检索重试"
+        return
+      }
       if (current?.id === "literature-review" && ["arxiv_search", "openalex_search"].includes(lower)) {
         if (!failed) searchCalls++
         const milestone = current.milestones.find((item) => item.id === "search")!