@dsh-bio/dsh-bio-gem 0.1.3 → 0.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -8
- package/docs/ARCHITECTURE.md +145 -116
- package/docs/DECISIONS-2026-09-21.md +76 -0
- package/docs/releases/v0.1.12.md +43 -0
- package/package.json +5 -3
- package/python/benchmark.py +3 -3
- package/python/biomass_tools.py +2 -2
- package/python/bootstrap_carveme.py +259 -0
- package/python/build.py +10 -2
- package/python/coherence.py +159 -0
- package/python/double_knockout.py +1 -1
- package/python/essential_scan.py +1 -1
- package/python/gapfind.py +413 -396
- package/python/gem_ops.py +64 -1
- package/python/l3_fix.py +4 -4
- package/python/ledger.py +1 -1
- package/python/model_card.py +3 -2
- package/python/precursor_scan.py +127 -0
- package/python/quality.py +577 -0
- package/python/sampling.py +269 -0
- package/python/sensitivity.py +2 -2
- package/python/validate.py +435 -409
- package/skills/gem-expert.md +3 -1
- package/src/capabilities.js +152 -0
- package/src/index.js +21 -2
- package/src/integration.js +507 -0
- package/src/jobs.js +5 -21
- package/src/python.js +113 -17
- package/src/tools.js +98 -22
package/skills/gem-expert.md
CHANGED
|
@@ -12,7 +12,8 @@ language: mixed
|
|
|
12
12
|
|---|---|
|
|
13
13
|
| 已有 SBML 模型文件,想知道概要(基因/反应/复制子)| `gem_report`(model 参数=绝对路径)|
|
|
14
14
|
| 验证模型质量(五道关卡:加载/元素平衡/生长真实性/表型/必需性抽检)| `gem_validate`(model + medium)|
|
|
15
|
-
|
|
|
15
|
+
| 模型质量审计(对标 MEMOTE 维度:blocked 反应/环路/元素平衡/孤儿与死端/覆盖率/连通性 + 启发式质量分)| `gem_quality`(model + 可选 medium;分项与 failed_checks 为准,quality_index 仅速览)|
|
|
16
|
+
| 模型在目标培养基不长,想知道为什么 | `gem_gapfind`(model + medium + substrates)**;先跑 `gem_precursor_scan` 确认阻塞层次**——它报「卡在哪个前体」(可生长即返无阻塞),比缺口清单更贴近根因 |
|
|
16
17
|
| gapfind 判 L3(内部路径)后自动补洞(白名单/MILP)| `gem_l3_fix`(model + medium + substrates;allow_math=true 才放数学连接;补后自动跑 G6 防能量循环)|
|
|
17
18
|
| 看/改 biomass(FBA 目标函数)| `gem_biomass`(action=inspect 只读组分/对照参考;apply 显式 profile + 三联对照,原文件不动可回滚)|
|
|
18
19
|
| 按缺口自动补洞(缺交换/转运规则修复)| `gem_gapfill`(model + medium)→ 补完重跑 `gem_validate` |
|
|
@@ -20,6 +21,7 @@ language: mixed
|
|
|
20
21
|
| 只有裸基因组 .fna,先要蛋白序列 | `gem_annotate`(fna → faa;官方优先 + pyrodigal 兜底)|
|
|
21
22
|
| 需要模型的全量必需基因清单 | `gem_essentiality`(FVA 预筛 + 手工敲除;medium 推荐 AB)|
|
|
22
23
|
| 跨条件通量对比(哪个反应真变了)| `gem_fluxscan`(区间制:FVA 区间+pFBA 点值,区间分离=硬结论,overlap=伪影禁止引用)|
|
|
24
|
+
| 通量分布采样(反应合理取值范围、稳态分布)| `gem_sample`(model + n + growth_floor_fraction;默认全空间采样,看近最优生长态传 0.9)|
|
|
23
25
|
| 量化模型不确定性(biomass/GAM 扰动下预测稳不稳)| `gem_sensitivity`(22 组合网格+稳定性三分类+单组分漂移;action=probe 秒级探测)|
|
|
24
26
|
| 查询/更新模型预测(必需性/表型预测追踪与实验兑现)| `gem_ledger`(list/query/update;预测默认 unverified,兑现后回填状态)|
|
|
25
27
|
| 两个模型规范对比(论文级基准表)| `gem_benchmark`(model_a+model_b:六关并列/生长/biomass 断供探针/必需性对比[退化侧只报结构]/表型/账本回填;export_md 落盘)|
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// dsh-bio-gem — capabilities 单源(single source of truth for tool manifest & capability metadata)
|
|
2
|
+
//
|
|
3
|
+
// 目的(外部评审共识,2026-09-21 裁决 §3.3):
|
|
4
|
+
// 1. 工具清单/能力分级/成本与副作用元数据集中一处,供 integration API(/v1/capabilities)
|
|
5
|
+
// 与 genie 宿主侧动态消费——消灭「工具数变化需同步 ≥12 处」的手工漂移。
|
|
6
|
+
// 2. 校验脚本 scripts/check-capabilities.mjs 强制本 MANIFEST 与 tools.js 真实注册集合一致;
|
|
7
|
+
// 文档计数(README/persona/面板)另有 count-audit 校验。
|
|
8
|
+
//
|
|
9
|
+
// 同步纪律:新增/删除工具时同步本文件(对应 category / capability / cost_class / network /
|
|
10
|
+
// mutability / summary),否则 check-capabilities 会报红。
|
|
11
|
+
//
|
|
12
|
+
// cost_class: light (<10s) | medium (10s–2min) | heavy (>2min)
|
|
13
|
+
// network: none | optional | required
|
|
14
|
+
// mutability: read_only | writes_output | model_mutating
|
|
15
|
+
// status: ready | experimental | data-not-initialized (依赖级状态由 integration 动态覆盖)
|
|
16
|
+
// requires: 动态依赖 id 列表(对齐 integration status 的 check id;缺省即 ready)
|
|
17
|
+
|
|
18
|
+
export const TOOLS_MANIFEST = [
|
|
19
|
+
// ---- build ----
|
|
20
|
+
{ name: 'gem_build', capability: 'gem.build.genome-to-model', category: 'build',
|
|
21
|
+
cost_class: 'heavy', network: 'optional', mutability: 'writes_output', status: 'ready',
|
|
22
|
+
requires: ['python.cobra', 'runtime.carveme'],
|
|
23
|
+
summary: '基因组→GEM 构建(CarveMe 自动自举 / gapseq WSL 档);后台 job + 进度' },
|
|
24
|
+
{ name: 'gem_annotate', capability: 'gem.build.annotate', category: 'build',
|
|
25
|
+
cost_class: 'medium', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
26
|
+
summary: '基因组注释→蛋白 FASTA(官方优先 + pyrodigal 兜底,纯 Windows)' },
|
|
27
|
+
{ name: 'gem_gapseq', capability: 'gem.build.gapseq-wsl', category: 'build',
|
|
28
|
+
cost_class: 'heavy', network: 'none', mutability: 'writes_output', status: 'experimental',
|
|
29
|
+
requires: ['runtime.gapseq'],
|
|
30
|
+
summary: 'gapseq 引擎原子四步(setup/launch/status/fetch,WSL2 依赖,实验性)' },
|
|
31
|
+
|
|
32
|
+
// ---- validate ----
|
|
33
|
+
{ name: 'gem_validate', capability: 'gem.validate.six-gate', category: 'validate',
|
|
34
|
+
cost_class: 'medium', network: 'none', mutability: 'read_only', status: 'ready',
|
|
35
|
+
requires: ['python.cobra'],
|
|
36
|
+
summary: '六道验证关卡 G0-G6(加载/平衡/生长/表型/必需性/ATP 泄漏)' },
|
|
37
|
+
{ name: 'gem_quality', capability: 'gem.validate.quality-report', category: 'validate',
|
|
38
|
+
cost_class: 'medium', network: 'none', mutability: 'read_only', status: 'ready',
|
|
39
|
+
requires: ['python.cobra'],
|
|
40
|
+
summary: '模型质量报告(gem-qi-v1:blocked/环路/平衡/孤儿/覆盖/连通性 + 启发式聚合分)' },
|
|
41
|
+
|
|
42
|
+
// ---- repair ----
|
|
43
|
+
{ name: 'gem_gapfind', capability: 'gem.repair.gap-diagnose', category: 'repair',
|
|
44
|
+
cost_class: 'medium', network: 'none', mutability: 'read_only', status: 'ready',
|
|
45
|
+
requires: ['python.cobra'],
|
|
46
|
+
summary: '缺口分级诊断 L1 缺交换 / L2 缺转运 / L3 内部路径' },
|
|
47
|
+
{ name: 'gem_gapfill', capability: 'gem.repair.gap-fill', category: 'repair',
|
|
48
|
+
cost_class: 'medium', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
49
|
+
requires: ['python.cobra'],
|
|
50
|
+
summary: 'L1/L2 规则级自动补洞(provenance 打标 + 防过补四闸门)' },
|
|
51
|
+
{ name: 'gem_l3_fix', capability: 'gem.repair.l3-pathway', category: 'repair',
|
|
52
|
+
cost_class: 'heavy', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
53
|
+
requires: ['python.cobra'],
|
|
54
|
+
summary: 'L3 内部路径补洞(白名单 + BiGG 反应式移植 + 证据分级 + G6 回滚)' },
|
|
55
|
+
{ name: 'gem_precursor_scan', capability: 'gem.repair.precursor-scan', category: 'repair',
|
|
56
|
+
cost_class: 'medium', network: 'none', mutability: 'read_only', status: 'ready',
|
|
57
|
+
requires: ['python.cobra'],
|
|
58
|
+
summary: '阻塞前体分析(不生长时逐前体移除测试定位阻塞点)' },
|
|
59
|
+
{ name: 'gem_phenotype', capability: 'gem.repair.phenotype-calibrate', category: 'repair',
|
|
60
|
+
cost_class: 'heavy', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
61
|
+
requires: ['python.cobra'],
|
|
62
|
+
summary: '表型回填迭代(Biolog/文献表校准 + L1/L2 自动修复 + 匹配率对比)' },
|
|
63
|
+
{ name: 'gem_biomass', capability: 'gem.repair.biomass-refine', category: 'repair',
|
|
64
|
+
cost_class: 'heavy', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
65
|
+
requires: ['python.cobra'],
|
|
66
|
+
summary: 'biomass 精修(inspect 组分对照 / apply 覆盖表 + 三联对照 + 回滚)' },
|
|
67
|
+
|
|
68
|
+
// ---- analysis ----
|
|
69
|
+
{ name: 'gem_essentiality', capability: 'gem.analysis.essentiality', category: 'analysis',
|
|
70
|
+
cost_class: 'heavy', network: 'none', mutability: 'read_only', status: 'ready',
|
|
71
|
+
requires: ['python.cobra'],
|
|
72
|
+
summary: '全量必需基因扫描(FVA 预筛 + 手工敲除;带 GPR 覆盖警告)' },
|
|
73
|
+
{ name: 'gem_fluxscan', capability: 'gem.analysis.flux-interval', category: 'analysis',
|
|
74
|
+
cost_class: 'heavy', network: 'none', mutability: 'read_only', status: 'ready',
|
|
75
|
+
requires: ['python.cobra'],
|
|
76
|
+
summary: '通量区间制(FVA 区间 + pFBA 点值;条件对比只认区间分离)' },
|
|
77
|
+
{ name: 'gem_sensitivity', capability: 'gem.analysis.sensitivity', category: 'analysis',
|
|
78
|
+
cost_class: 'heavy', network: 'none', mutability: 'read_only', status: 'ready',
|
|
79
|
+
requires: ['python.cobra'],
|
|
80
|
+
summary: '结构性灵敏度(GAM×biomass 网格 + 稳定性三分类)' },
|
|
81
|
+
{ name: 'gem_secretion', capability: 'gem.analysis.secretion', category: 'analysis',
|
|
82
|
+
cost_class: 'medium', network: 'none', mutability: 'read_only', status: 'ready',
|
|
83
|
+
requires: ['python.cobra'],
|
|
84
|
+
summary: '可分泌代谢物谱(production envelope 扫描;纯拓扑边界声明)' },
|
|
85
|
+
{ name: 'gem_double_knockout', capability: 'gem.analysis.double-knockout', category: 'analysis',
|
|
86
|
+
cost_class: 'heavy', network: 'none', mutability: 'read_only', status: 'ready',
|
|
87
|
+
requires: ['python.cobra'],
|
|
88
|
+
summary: '双敲合成致死(GPR 穷尽先验 + 全扫预算)' },
|
|
89
|
+
{ name: 'gem_enrichment', capability: 'gem.analysis.enrichment', category: 'analysis',
|
|
90
|
+
cost_class: 'light', network: 'none', mutability: 'read_only', status: 'ready',
|
|
91
|
+
requires: ['python.cobra'],
|
|
92
|
+
summary: '必需基因通路富集(超几何 + BH FDR;通路源 = SBML groups)' },
|
|
93
|
+
{ name: 'gem_sample', capability: 'gem.analysis.sampling', category: 'analysis',
|
|
94
|
+
cost_class: 'heavy', network: 'none', mutability: 'read_only', status: 'ready',
|
|
95
|
+
requires: ['python.cobra'],
|
|
96
|
+
summary: '通量空间采样(ACHR/OptGP;growth_floor 受限空间;边界声明)' },
|
|
97
|
+
|
|
98
|
+
// ---- export ----
|
|
99
|
+
{ name: 'gem_targets', capability: 'gem.export.targets', category: 'export',
|
|
100
|
+
cost_class: 'light', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
101
|
+
summary: '靶点清单规范导出(11 字段锁定 schema;计数闭合)' },
|
|
102
|
+
|
|
103
|
+
// ---- assets ----
|
|
104
|
+
{ name: 'gem_media_resolve', capability: 'gem.asset.medium-resolve', category: 'assets',
|
|
105
|
+
cost_class: 'light', network: 'none', mutability: 'read_only', status: 'ready',
|
|
106
|
+
requires: ['python.cobra'],
|
|
107
|
+
summary: '介质解析(自然名 → EX ID;跨引擎命名空间)' },
|
|
108
|
+
{ name: 'gem_ledger', capability: 'gem.asset.ledger', category: 'assets',
|
|
109
|
+
cost_class: 'light', network: 'none', mutability: 'writes_output', status: 'ready',
|
|
110
|
+
summary: '预测账本(list/query/update;幂等;基率追踪)' },
|
|
111
|
+
{ name: 'gem_benchmark', capability: 'gem.asset.benchmark', category: 'assets',
|
|
112
|
+
cost_class: 'heavy', network: 'optional', mutability: 'writes_output', status: 'ready',
|
|
113
|
+
requires: ['python.cobra'],
|
|
114
|
+
summary: '两模型基准对比(六关并列/生长/必需性/表型/账本回填;支持 bigg: 下载)' },
|
|
115
|
+
{ name: 'gem_report', capability: 'gem.asset.report', category: 'assets',
|
|
116
|
+
cost_class: 'light', network: 'none', mutability: 'read_only', status: 'ready',
|
|
117
|
+
requires: ['python.cobra'],
|
|
118
|
+
summary: '模型摘要 + 账本基率' },
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
export const CONTRACT_VERSION = '1'
|
|
122
|
+
|
|
123
|
+
/** 组装 capabilities 报告(静态 manifest + 动态依赖状态覆盖)。 */
|
|
124
|
+
export function buildCapabilitiesReport({ pluginVersion, checks = [] } = {}) {
|
|
125
|
+
const checkStatus = new Map(checks.map((c) => [c.id, c.status]))
|
|
126
|
+
const tools = TOOLS_MANIFEST.map((t) => {
|
|
127
|
+
const missingDeps = (t.requires ?? []).filter((id) => {
|
|
128
|
+
const st = checkStatus.get(id)
|
|
129
|
+
return st !== undefined && st !== 'ok'
|
|
130
|
+
})
|
|
131
|
+
const effectiveStatus = missingDeps.length > 0 ? 'unavailable' : (t.status ?? 'ready')
|
|
132
|
+
return {
|
|
133
|
+
name: t.name,
|
|
134
|
+
capability: t.capability,
|
|
135
|
+
category: t.category,
|
|
136
|
+
cost_class: t.cost_class,
|
|
137
|
+
network: t.network,
|
|
138
|
+
mutability: t.mutability,
|
|
139
|
+
status: effectiveStatus,
|
|
140
|
+
summary: t.summary,
|
|
141
|
+
...(t.requires ? { requires: t.requires } : {}),
|
|
142
|
+
...(missingDeps.length > 0 ? { missing_dependencies: missingDeps } : {}),
|
|
143
|
+
}
|
|
144
|
+
})
|
|
145
|
+
return {
|
|
146
|
+
contract_version: CONTRACT_VERSION,
|
|
147
|
+
plugin_id: 'dsh-bio-gem',
|
|
148
|
+
plugin_version: pluginVersion,
|
|
149
|
+
tool_count: tools.length,
|
|
150
|
+
tools,
|
|
151
|
+
}
|
|
152
|
+
}
|
package/src/index.js
CHANGED
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
// 注入 tools(5 语义化工具:gem_report/validate/gapfind/gapfill/build)+ skills(gem-expert)。
|
|
3
3
|
import { registerTools } from './tools.js'
|
|
4
4
|
import { registerSkills } from './skills.js'
|
|
5
|
+
import { registerIntegrationRoutes, createIntegrationService } from './integration.js'
|
|
5
6
|
|
|
6
7
|
/** Cordis 插件名(cordis.patch.yml row id 同名)。 */
|
|
7
8
|
export const name = 'dsh-bio-gem'
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* 静态注入只列**必选**服务(数组形式是 cordis 唯一支持的「服务名列表」写法;
|
|
12
|
+
* `{ required, optional }` 的对象形式会被 cordis 当成「服务名 → 配置」字典,
|
|
13
|
+
* 导致插件永远 pending —— 实测:dsh boot 报
|
|
14
|
+
* `@dsh-bio/dsh-bio-gem: pending (waiting for services: required, optional)`)。
|
|
15
|
+
*
|
|
16
|
+
* `webServer` 是**可选**服务(非 web 部署不提供),改用 apply 内的动态注入
|
|
17
|
+
* `ctx.inject(['webServer'], cb)`(官方 dsh 插件同款模式):服务可用时注册
|
|
18
|
+
* 只读 integration 路由,不可用时 23 个工具与 skill 照常注册。
|
|
19
|
+
*/
|
|
10
20
|
export const inject = ['tools', 'skills']
|
|
11
21
|
|
|
12
22
|
/**
|
|
@@ -16,4 +26,13 @@ export const inject = ['tools', 'skills']
|
|
|
16
26
|
export function apply(ctx) {
|
|
17
27
|
registerTools(ctx)
|
|
18
28
|
registerSkills(ctx)
|
|
19
|
-
|
|
29
|
+
|
|
30
|
+
const service = createIntegrationService()
|
|
31
|
+
ctx.inject(['webServer'], (webCtx) => {
|
|
32
|
+
webCtx.effect(() => registerIntegrationRoutes(webCtx, { service }), 'dsh-bio-gem: integration API routes')
|
|
33
|
+
// 延迟预热(**不在插件加载期**执行,不阻塞启动):启动 ~8s 后后台跑一次只读探测,
|
|
34
|
+
// 让面板首次打开即命中 60s 缓存,避免首次冷探测(含 WSL 探测)被消费端超时截断。
|
|
35
|
+
const warmup = setTimeout(() => { void service.status().catch(() => {}) }, 8_000)
|
|
36
|
+
webCtx.effect(() => () => clearTimeout(warmup), 'dsh-bio-gem: runtime probe warm-up')
|
|
37
|
+
})
|
|
38
|
+
}
|