@researai/deepscientist 1.5.16 → 1.6.0
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/AGENTS.md +309 -130
- package/AISB/catalog/aisb.b1.agentic_coding.yaml +244 -0
- package/AISB/catalog/aisb.b10.climate_earth.yaml +235 -0
- package/AISB/catalog/aisb.b11.model_efficiency.yaml +231 -0
- package/AISB/catalog/aisb.b12.embodied_ai.yaml +238 -0
- package/AISB/catalog/aisb.b2.agent_systems.yaml +229 -0
- package/AISB/catalog/aisb.b3.self_evolving_rl.yaml +237 -0
- package/AISB/catalog/aisb.b4.lm_reasoning.yaml +240 -0
- package/AISB/catalog/aisb.b5.math_proof.yaml +235 -0
- package/AISB/catalog/aisb.b6.research_process.yaml +243 -0
- package/AISB/catalog/aisb.b7.multimodal_fusion.yaml +232 -0
- package/AISB/catalog/aisb.b8.lifesci_drug.yaml +275 -0
- package/AISB/catalog/aisb.b9.material_science.yaml +237 -0
- package/AISB/catalog/aisb.t3.001_savvy.yaml +159 -0
- package/AISB/catalog/aisb.t3.001_savvy.zh.yaml +121 -0
- package/AISB/catalog/aisb.t3.002_pinet.yaml +189 -0
- package/AISB/catalog/aisb.t3.002_pinet.zh.yaml +130 -0
- package/AISB/catalog/aisb.t3.004_decentralattn.yaml +184 -0
- package/AISB/catalog/aisb.t3.004_decentralattn.zh.yaml +153 -0
- package/AISB/catalog/aisb.t3.005_tsae.yaml +193 -0
- package/AISB/catalog/aisb.t3.005_tsae.zh.yaml +139 -0
- package/AISB/catalog/aisb.t3.006_physense.yaml +194 -0
- package/AISB/catalog/aisb.t3.006_physense.zh.yaml +118 -0
- package/AISB/catalog/aisb.t3.007_reasoningiqa.yaml +169 -0
- package/AISB/catalog/aisb.t3.007_reasoningiqa.zh.yaml +133 -0
- package/AISB/catalog/aisb.t3.008_meanflows.yaml +188 -0
- package/AISB/catalog/aisb.t3.008_meanflows.zh.yaml +140 -0
- package/AISB/catalog/aisb.t3.009_scoremissing.yaml +179 -0
- package/AISB/catalog/aisb.t3.009_scoremissing.zh.yaml +119 -0
- package/AISB/catalog/aisb.t3.010_suitabilityfilter.yaml +221 -0
- package/AISB/catalog/aisb.t3.010_suitabilityfilter.zh.yaml +141 -0
- package/AISB/catalog/aisb.t3.011_osd.yaml +206 -0
- package/AISB/catalog/aisb.t3.011_osd.zh.yaml +163 -0
- package/AISB/catalog/aisb.t3.012_efficientqat.yaml +206 -0
- package/AISB/catalog/aisb.t3.012_efficientqat.zh.yaml +159 -0
- package/AISB/catalog/aisb.t3.013_appl.yaml +152 -0
- package/AISB/catalog/aisb.t3.013_appl.zh.yaml +126 -0
- package/AISB/catalog/aisb.t3.014_piguard.yaml +207 -0
- package/AISB/catalog/aisb.t3.014_piguard.zh.yaml +164 -0
- package/AISB/catalog/aisb.t3.015_frspec.yaml +209 -0
- package/AISB/catalog/aisb.t3.015_frspec.zh.yaml +163 -0
- package/AISB/catalog/aisb.t3.016_mathfusion.yaml +166 -0
- package/AISB/catalog/aisb.t3.016_mathfusion.zh.yaml +145 -0
- package/AISB/catalog/aisb.t3.017_multimodalglp.yaml +171 -0
- package/AISB/catalog/aisb.t3.017_multimodalglp.zh.yaml +122 -0
- package/AISB/catalog/aisb.t3.018_cotsynth.yaml +206 -0
- package/AISB/catalog/aisb.t3.018_cotsynth.zh.yaml +162 -0
- package/AISB/catalog/aisb.t3.019_dyscaleut.yaml +211 -0
- package/AISB/catalog/aisb.t3.019_dyscaleut.zh.yaml +148 -0
- package/AISB/catalog/aisb.t3.020_aristotle.yaml +173 -0
- package/AISB/catalog/aisb.t3.020_aristotle.zh.yaml +119 -0
- package/AISB/catalog/aisb.t3.021_tokenrecycling.yaml +160 -0
- package/AISB/catalog/aisb.t3.021_tokenrecycling.zh.yaml +129 -0
- package/AISB/catalog/aisb.t3.022_chainofreasoning.yaml +204 -0
- package/AISB/catalog/aisb.t3.022_chainofreasoning.zh.yaml +161 -0
- package/AISB/catalog/aisb.t3.023_guidedembed.yaml +211 -0
- package/AISB/catalog/aisb.t3.023_guidedembed.zh.yaml +189 -0
- package/AISB/catalog/aisb.t3.024_outputcentric.yaml +148 -0
- package/AISB/catalog/aisb.t3.024_outputcentric.zh.yaml +131 -0
- package/AISB/catalog/aisb.t3.025_deeper.yaml +143 -0
- package/AISB/catalog/aisb.t3.025_deeper.zh.yaml +116 -0
- package/AISB/catalog/aisb.t3.026_gartkg.yaml +195 -0
- package/AISB/catalog/aisb.t3.026_gartkg.zh.yaml +127 -0
- package/AISB/catalog/aisb.t3.027_citeeval.yaml +182 -0
- package/AISB/catalog/aisb.t3.027_citeeval.zh.yaml +135 -0
- package/AISB/catalog/aisb.t3.028_sbam.yaml +206 -0
- package/AISB/catalog/aisb.t3.028_sbam.zh.yaml +166 -0
- package/AISB/catalog/aisb.t3.029_cdqgeoembed.yaml +224 -0
- package/AISB/catalog/aisb.t3.029_cdqgeoembed.zh.yaml +142 -0
- package/AISB/catalog/aisb.t3.030_processrm.yaml +211 -0
- package/AISB/catalog/aisb.t3.030_processrm.zh.yaml +166 -0
- package/AISB/catalog/aisb.t3.031_circuitstability.yaml +172 -0
- package/AISB/catalog/aisb.t3.031_circuitstability.zh.yaml +134 -0
- package/AISB/catalog/aisb.t3.032_ptsolver.yaml +169 -0
- package/AISB/catalog/aisb.t3.032_ptsolver.zh.yaml +135 -0
- package/AISB/catalog/aisb.t3.033_gcse.yaml +144 -0
- package/AISB/catalog/aisb.t3.033_gcse.zh.yaml +126 -0
- package/AISB/catalog/aisb.t3.034_ensemblewm.yaml +183 -0
- package/AISB/catalog/aisb.t3.034_ensemblewm.zh.yaml +146 -0
- package/AISB/catalog/aisb.t3.035_moralvalueswa.yaml +207 -0
- package/AISB/catalog/aisb.t3.035_moralvalueswa.zh.yaml +165 -0
- package/AISB/catalog/aisb.t3.036_weakstrongpref.yaml +210 -0
- package/AISB/catalog/aisb.t3.036_weakstrongpref.zh.yaml +194 -0
- package/AISB/catalog/aisb.t3.037_dementiamask.yaml +172 -0
- package/AISB/catalog/aisb.t3.037_dementiamask.zh.yaml +132 -0
- package/AISB/catalog/aisb.t3.038_tinysam.yaml +284 -0
- package/AISB/catalog/aisb.t3.038_tinysam.zh.yaml +240 -0
- package/AISB/catalog/aisb.t3.039_calf.yaml +224 -0
- package/AISB/catalog/aisb.t3.039_calf.zh.yaml +194 -0
- package/AISB/catalog/aisb.t3.040_graniteguardian.yaml +199 -0
- package/AISB/catalog/aisb.t3.040_graniteguardian.zh.yaml +174 -0
- package/AISB/catalog/aisb.t3.041_amdm.yaml +149 -0
- package/AISB/catalog/aisb.t3.041_amdm.zh.yaml +137 -0
- package/AISB/catalog/aisb.t3.042_xpatch.yaml +216 -0
- package/AISB/catalog/aisb.t3.042_xpatch.zh.yaml +182 -0
- package/AISB/catalog/aisb.t3.043_vhm.yaml +268 -0
- package/AISB/catalog/aisb.t3.043_vhm.zh.yaml +193 -0
- package/AISB/catalog/aisb.t3.044_rgvi.yaml +224 -0
- package/AISB/catalog/aisb.t3.044_rgvi.zh.yaml +176 -0
- package/AISB/catalog/aisb.t3.045_pslstm.yaml +203 -0
- package/AISB/catalog/aisb.t3.045_pslstm.zh.yaml +179 -0
- package/AISB/catalog/aisb.t3.046_nonstatts.yaml +208 -0
- package/AISB/catalog/aisb.t3.046_nonstatts.zh.yaml +194 -0
- package/AISB/catalog/aisb.t3.047_timepfn.yaml +156 -0
- package/AISB/catalog/aisb.t3.047_timepfn.zh.yaml +124 -0
- package/AISB/catalog/aisb.t3.048_proxyspex.yaml +148 -0
- package/AISB/catalog/aisb.t3.048_proxyspex.zh.yaml +125 -0
- package/AISB/catalog/aisb.t3.049_hogwildinference.yaml +183 -0
- package/AISB/catalog/aisb.t3.049_hogwildinference.zh.yaml +138 -0
- package/AISB/catalog/aisb.t3.050_causalpfn.yaml +214 -0
- package/AISB/catalog/aisb.t3.050_causalpfn.zh.yaml +190 -0
- package/AISB/catalog/aisb.t3.051_flashtp.yaml +169 -0
- package/AISB/catalog/aisb.t3.051_flashtp.zh.yaml +124 -0
- package/AISB/catalog/aisb.t3.052_nsdiff.yaml +155 -0
- package/AISB/catalog/aisb.t3.052_nsdiff.zh.yaml +138 -0
- package/AISB/catalog/aisb.t3.053_k2vae.yaml +158 -0
- package/AISB/catalog/aisb.t3.053_k2vae.zh.yaml +132 -0
- package/AISB/catalog/aisb.t3.054_timebase.yaml +178 -0
- package/AISB/catalog/aisb.t3.054_timebase.zh.yaml +158 -0
- package/AISB/catalog/aisb.t3.055_csbrain.yaml +238 -0
- package/AISB/catalog/aisb.t3.055_csbrain.zh.yaml +184 -0
- package/AISB/catalog/aisb.t3.056_infosam.yaml +224 -0
- package/AISB/catalog/aisb.t3.056_infosam.zh.yaml +189 -0
- package/AISB/catalog/aisb.t3.057_mdreid.yaml +129 -0
- package/AISB/catalog/aisb.t3.057_mdreid.zh.yaml +117 -0
- package/AISB/catalog/aisb.t3.058_mindglitch.yaml +171 -0
- package/AISB/catalog/aisb.t3.058_mindglitch.zh.yaml +145 -0
- package/AISB/catalog/aisb.t3.059_selfsupervised.yaml +154 -0
- package/AISB/catalog/aisb.t3.059_selfsupervised.zh.yaml +125 -0
- package/AISB/catalog/aisb.t3.060_iaggad.yaml +121 -0
- package/AISB/catalog/aisb.t3.060_iaggad.zh.yaml +100 -0
- package/AISB/catalog/aisb.t3.061_hsgkn.yaml +136 -0
- package/AISB/catalog/aisb.t3.061_hsgkn.zh.yaml +113 -0
- package/AISB/catalog/aisb.t3.062_visionts.yaml +237 -0
- package/AISB/catalog/aisb.t3.062_visionts.zh.yaml +216 -0
- package/AISB/catalog/aisb.t3.063_tsrag.yaml +162 -0
- package/AISB/catalog/aisb.t3.063_tsrag.zh.yaml +138 -0
- package/AISB/catalog/aisb.t3.064_pir.yaml +221 -0
- package/AISB/catalog/aisb.t3.064_pir.zh.yaml +197 -0
- package/AISB/catalog/aisb.t3.065_proteinbinding.yaml +234 -0
- package/AISB/catalog/aisb.t3.065_proteinbinding.zh.yaml +167 -0
- package/AISB/catalog/aisb.t3.066_tropicalattention.yaml +267 -0
- package/AISB/catalog/aisb.t3.066_tropicalattention.zh.yaml +229 -0
- package/AISB/catalog/aisb.t3.067_kanad.yaml +193 -0
- package/AISB/catalog/aisb.t3.067_kanad.zh.yaml +167 -0
- package/AISB/catalog/aisb.t3.068_sempo.yaml +187 -0
- package/AISB/catalog/aisb.t3.068_sempo.zh.yaml +148 -0
- package/AISB/catalog/aisb.t3.069_treehfd.yaml +129 -0
- package/AISB/catalog/aisb.t3.069_treehfd.zh.yaml +111 -0
- package/AISB/catalog/aisb.t3.070_certifiedunlearning.yaml +224 -0
- package/AISB/catalog/aisb.t3.070_certifiedunlearning.zh.yaml +171 -0
- package/AISB/catalog/aisb.t3.071_neuralmjd.yaml +142 -0
- package/AISB/catalog/aisb.t3.071_neuralmjd.zh.yaml +120 -0
- package/AISB/catalog/aisb.t3.072_fedgmt.yaml +181 -0
- package/AISB/catalog/aisb.t3.072_fedgmt.zh.yaml +158 -0
- package/AISB/catalog/aisb.t3.073_rld.yaml +161 -0
- package/AISB/catalog/aisb.t3.073_rld.zh.yaml +129 -0
- package/AISB/catalog/aisb.t3.074_lsvi.yaml +163 -0
- package/AISB/catalog/aisb.t3.074_lsvi.zh.yaml +129 -0
- package/AISB/catalog/aisb.t3.075_treeslicedentropy.yaml +201 -0
- package/AISB/catalog/aisb.t3.075_treeslicedentropy.zh.yaml +148 -0
- package/AISB/catalog/aisb.t3.076_aanet.yaml +169 -0
- package/AISB/catalog/aisb.t3.076_aanet.zh.yaml +129 -0
- package/AISB/catalog/aisb.t3.077_cmnn.yaml +199 -0
- package/AISB/catalog/aisb.t3.077_cmnn.zh.yaml +165 -0
- package/AISB/catalog/aisb.t3.078_conformalanomaly.yaml +146 -0
- package/AISB/catalog/aisb.t3.078_conformalanomaly.zh.yaml +117 -0
- package/AISB/catalog/aisb.t3.079_dpfkmeans.yaml +131 -0
- package/AISB/catalog/aisb.t3.079_dpfkmeans.zh.yaml +104 -0
- package/AISB/catalog/aisb.t3.080_latentscorereweight.yaml +169 -0
- package/AISB/catalog/aisb.t3.080_latentscorereweight.zh.yaml +123 -0
- package/AISB/catalog/aisb.t3.081_qmamba.yaml +150 -0
- package/AISB/catalog/aisb.t3.081_qmamba.zh.yaml +117 -0
- package/AISB/catalog/aisb.t3.082_onlinellmrouting.yaml +160 -0
- package/AISB/catalog/aisb.t3.082_onlinellmrouting.zh.yaml +133 -0
- package/AISB/catalog/aisb.t3.083_starformer.yaml +178 -0
- package/AISB/catalog/aisb.t3.083_starformer.zh.yaml +140 -0
- package/AISB/catalog/aisb.t3.084_ift.yaml +139 -0
- package/AISB/catalog/aisb.t3.084_ift.zh.yaml +111 -0
- package/AISB/catalog/aisb.t3.085_neuralsurv.yaml +183 -0
- package/AISB/catalog/aisb.t3.085_neuralsurv.zh.yaml +143 -0
- package/AISB/catalog/aisb.t3.086_stella.yaml +197 -0
- package/AISB/catalog/aisb.t3.086_stella.zh.yaml +142 -0
- package/AISB/catalog/aisb.t3.087_moses.yaml +167 -0
- package/AISB/catalog/aisb.t3.087_moses.zh.yaml +132 -0
- package/AISB/catalog/aisb.t3.088_channelnorm.yaml +140 -0
- package/AISB/catalog/aisb.t3.088_channelnorm.zh.yaml +109 -0
- package/AISB/catalog/aisb.t3.089_causalvelocity.yaml +730 -0
- package/AISB/catalog/aisb.t3.089_causalvelocity.zh.yaml +668 -0
- package/AISB/catalog/aisb.t3.090_rstib.yaml +144 -0
- package/AISB/catalog/aisb.t3.090_rstib.zh.yaml +109 -0
- package/AISB/catalog/aisb.t3.091_timeawarecausal.yaml +132 -0
- package/AISB/catalog/aisb.t3.091_timeawarecausal.zh.yaml +107 -0
- package/AISB/catalog/aisb.t3.092_kmeanslocalopt.yaml +138 -0
- package/AISB/catalog/aisb.t3.092_kmeanslocalopt.zh.yaml +110 -0
- package/AISB/catalog/aisb.t3.093_fedwmsam.yaml +134 -0
- package/AISB/catalog/aisb.t3.093_fedwmsam.zh.yaml +106 -0
- package/AISB/catalog/aisb.t3.094_boundre.yaml +147 -0
- package/AISB/catalog/aisb.t3.094_boundre.zh.yaml +114 -0
- package/AISB/catalog/aisb.t3.095_fastfeaturecp.yaml +153 -0
- package/AISB/catalog/aisb.t3.095_fastfeaturecp.zh.yaml +118 -0
- package/AISB/catalog/aisb.t3.096_m3svm.yaml +189 -0
- package/AISB/catalog/aisb.t3.096_m3svm.zh.yaml +149 -0
- package/AISB/catalog/aisb.t3.097_wassersteintl.yaml +212 -0
- package/AISB/catalog/aisb.t3.097_wassersteintl.zh.yaml +169 -0
- package/AISB/catalog/aisb.t3.098_xmahalanobis.yaml +171 -0
- package/AISB/catalog/aisb.t3.098_xmahalanobis.zh.yaml +127 -0
- package/AISB/catalog/aisb.t3.099_ollalanding.yaml +248 -0
- package/AISB/catalog/aisb.t3.099_ollalanding.zh.yaml +182 -0
- package/AISB/catalog/aisb.t3.100_invmissingdata.yaml +179 -0
- package/AISB/catalog/aisb.t3.100_invmissingdata.zh.yaml +150 -0
- package/AISB/catalog/aisb.t3.101_acia.yaml +164 -0
- package/AISB/catalog/aisb.t3.101_acia.zh.yaml +109 -0
- package/AISB/catalog/aisb.t3.102_stochasticff.yaml +178 -0
- package/AISB/catalog/aisb.t3.102_stochasticff.zh.yaml +130 -0
- package/AISB/catalog/aisb.t3.103_qdcp.yaml +150 -0
- package/AISB/catalog/aisb.t3.103_qdcp.zh.yaml +116 -0
- package/AISB/catalog/aisb.t3.104_balancedactiveinf.yaml +137 -0
- package/AISB/catalog/aisb.t3.104_balancedactiveinf.zh.yaml +104 -0
- package/AISB/catalog/aisb.t3.105_binaryclasseval.yaml +161 -0
- package/AISB/catalog/aisb.t3.105_binaryclasseval.zh.yaml +130 -0
- package/AISB/image/001_aisb.t3.001_savvy.jpg +0 -0
- package/AISB/image/002_aisb.t3.002_pinet.jpg +0 -0
- package/AISB/image/003_aisb.t3.003_dmsqd.jpg +0 -0
- package/AISB/image/004_aisb.t3.004_decentralattn.jpg +0 -0
- package/AISB/image/005_aisb.t3.005_tsae.jpg +0 -0
- package/AISB/image/006_aisb.t3.006_physense.jpg +0 -0
- package/AISB/image/007_aisb.t3.007_reasoningiqa.jpg +0 -0
- package/AISB/image/008_aisb.t3.008_meanflows.jpg +0 -0
- package/AISB/image/009_aisb.t3.009_scoremissing.jpg +0 -0
- package/AISB/image/010_aisb.t3.010_suitabilityfilter.jpg +0 -0
- package/AISB/image/011_aisb.t3.011_osd.jpg +0 -0
- package/AISB/image/012_aisb.t3.012_efficientqat.jpg +0 -0
- package/AISB/image/013_aisb.t3.013_appl.jpg +0 -0
- package/AISB/image/014_aisb.t3.014_piguard.jpg +0 -0
- package/AISB/image/015_aisb.t3.015_frspec.jpg +0 -0
- package/AISB/image/016_aisb.t3.016_mathfusion.jpg +0 -0
- package/AISB/image/017_aisb.t3.017_multimodalglp.jpg +0 -0
- package/AISB/image/018_aisb.t3.018_cotsynth.jpg +0 -0
- package/AISB/image/019_aisb.t3.019_dyscaleut.jpg +0 -0
- package/AISB/image/020_aisb.t3.020_aristotle.jpg +0 -0
- package/AISB/image/021_aisb.t3.021_tokenrecycling.jpg +0 -0
- package/AISB/image/022_aisb.t3.022_chainofreasoning.jpg +0 -0
- package/AISB/image/023_aisb.t3.023_guidedembed.jpg +0 -0
- package/AISB/image/024_aisb.t3.024_outputcentric.jpg +0 -0
- package/AISB/image/025_aisb.t3.025_deeper.jpg +0 -0
- package/AISB/image/026_aisb.t3.026_gartkg.jpg +0 -0
- package/AISB/image/027_aisb.t3.027_citeeval.jpg +0 -0
- package/AISB/image/028_aisb.t3.028_sbam.jpg +0 -0
- package/AISB/image/029_aisb.t3.029_cdqgeoembed.jpg +0 -0
- package/AISB/image/030_aisb.t3.030_processrm.jpg +0 -0
- package/AISB/image/031_aisb.t3.031_circuitstability.jpg +0 -0
- package/AISB/image/032_aisb.t3.032_ptsolver.jpg +0 -0
- package/AISB/image/033_aisb.t3.033_gcse.jpg +0 -0
- package/AISB/image/034_aisb.t3.034_ensemblewm.jpg +0 -0
- package/AISB/image/035_aisb.t3.035_moralvalueswa.jpg +0 -0
- package/AISB/image/036_aisb.t3.036_weakstrongpref.jpg +0 -0
- package/AISB/image/037_aisb.t3.037_dementiamask.jpg +0 -0
- package/AISB/image/038_aisb.t3.038_tinysam.jpg +0 -0
- package/AISB/image/039_aisb.t3.039_calf.jpg +0 -0
- package/AISB/image/040_aisb.t3.040_graniteguardian.jpg +0 -0
- package/AISB/image/041_aisb.t3.041_amdm.jpg +0 -0
- package/AISB/image/042_aisb.t3.042_xpatch.jpg +0 -0
- package/AISB/image/043_aisb.t3.043_vhm.jpg +0 -0
- package/AISB/image/044_aisb.t3.044_rgvi.jpg +0 -0
- package/AISB/image/045_aisb.t3.045_pslstm.jpg +0 -0
- package/AISB/image/046_aisb.t3.046_nonstatts.jpg +0 -0
- package/AISB/image/047_aisb.t3.047_timepfn.jpg +0 -0
- package/AISB/image/048_aisb.t3.048_proxyspex.jpg +0 -0
- package/AISB/image/049_aisb.t3.049_hogwildinference.jpg +0 -0
- package/AISB/image/050_aisb.t3.050_causalpfn.jpg +0 -0
- package/AISB/image/051_aisb.t3.051_flashtp.jpg +0 -0
- package/AISB/image/052_aisb.t3.052_nsdiff.jpg +0 -0
- package/AISB/image/053_aisb.t3.053_k2vae.jpg +0 -0
- package/AISB/image/054_aisb.t3.054_timebase.jpg +0 -0
- package/AISB/image/055_aisb.t3.055_csbrain.jpg +0 -0
- package/AISB/image/056_aisb.t3.056_infosam.jpg +0 -0
- package/AISB/image/057_aisb.t3.057_mdreid.jpg +0 -0
- package/AISB/image/058_aisb.t3.058_mindglitch.jpg +0 -0
- package/AISB/image/059_aisb.t3.059_selfsupervised.jpg +0 -0
- package/AISB/image/060_aisb.t3.060_iaggad.jpg +0 -0
- package/AISB/image/061_aisb.t3.061_hsgkn.jpg +0 -0
- package/AISB/image/062_aisb.t3.062_visionts.jpg +0 -0
- package/AISB/image/063_aisb.t3.063_tsrag.jpg +0 -0
- package/AISB/image/064_aisb.t3.064_pir.jpg +0 -0
- package/AISB/image/065_aisb.t3.065_proteinbinding.jpg +0 -0
- package/AISB/image/066_aisb.t3.066_tropicalattention.jpg +0 -0
- package/AISB/image/067_aisb.t3.067_kanad.jpg +0 -0
- package/AISB/image/068_aisb.t3.068_sempo.jpg +0 -0
- package/AISB/image/069_aisb.t3.069_treehfd.jpg +0 -0
- package/AISB/image/070_aisb.t3.070_certifiedunlearning.jpg +0 -0
- package/AISB/image/071_aisb.t3.071_neuralmjd.jpg +0 -0
- package/AISB/image/072_aisb.t3.072_fedgmt.jpg +0 -0
- package/AISB/image/073_aisb.t3.073_rld.jpg +0 -0
- package/AISB/image/074_aisb.t3.074_lsvi.jpg +0 -0
- package/AISB/image/075_aisb.t3.075_treeslicedentropy.jpg +0 -0
- package/AISB/image/076_aisb.t3.076_aanet.jpg +0 -0
- package/AISB/image/077_aisb.t3.077_cmnn.jpg +0 -0
- package/AISB/image/078_aisb.t3.078_conformalanomaly.jpg +0 -0
- package/AISB/image/079_aisb.t3.079_dpfkmeans.jpg +0 -0
- package/AISB/image/080_aisb.t3.080_latentscorereweight.jpg +0 -0
- package/AISB/image/081_aisb.t3.081_qmamba.jpg +0 -0
- package/AISB/image/082_aisb.t3.082_onlinellmrouting.jpg +0 -0
- package/AISB/image/083_aisb.t3.083_starformer.jpg +0 -0
- package/AISB/image/084_aisb.t3.084_ift.jpg +0 -0
- package/AISB/image/085_aisb.t3.085_neuralsurv.jpg +0 -0
- package/AISB/image/086_aisb.t3.086_stella.jpg +0 -0
- package/AISB/image/087_aisb.t3.087_moses.jpg +0 -0
- package/AISB/image/088_aisb.t3.088_channelnorm.jpg +0 -0
- package/AISB/image/089_aisb.t3.089_causalvelocity.jpg +0 -0
- package/AISB/image/090_aisb.t3.090_rstib.jpg +0 -0
- package/AISB/image/091_aisb.t3.091_timeawarecausal.jpg +0 -0
- package/AISB/image/092_aisb.t3.092_kmeanslocalopt.jpg +0 -0
- package/AISB/image/093_aisb.t3.093_fedwmsam.jpg +0 -0
- package/AISB/image/094_aisb.t3.094_boundre.jpg +0 -0
- package/AISB/image/095_aisb.t3.095_fastfeaturecp.jpg +0 -0
- package/AISB/image/096_aisb.t3.096_m3svm.jpg +0 -0
- package/AISB/image/097_aisb.t3.097_wassersteintl.jpg +0 -0
- package/AISB/image/098_aisb.t3.098_xmahalanobis.jpg +0 -0
- package/AISB/image/099_aisb.t3.099_ollalanding.jpg +0 -0
- package/AISB/image/100_aisb.t3.100_invmissingdata.jpg +0 -0
- package/AISB/image/101_aisb.t3.101_acia.jpg +0 -0
- package/AISB/image/102_aisb.t3.102_stochasticff.jpg +0 -0
- package/AISB/image/103_aisb.t3.103_qdcp.jpg +0 -0
- package/AISB/image/104_aisb.t3.104_balancedactiveinf.jpg +0 -0
- package/AISB/image/105_aisb.t3.105_binaryclasseval.jpg +0 -0
- package/AISB/image/106_aisb.t1.reasoning_lite.jpg +0 -0
- package/AISB/image/107_aisb.t2.paper_audit.jpg +0 -0
- package/AISB/image/108_aisb.t3.multi_gpu_search.jpg +0 -0
- package/AISB/image/109_aisb.t3.tdc_admet.jpg +0 -0
- package/AISB/image/aisb.b1.agentic_coding.svg +16 -0
- package/AISB/image/aisb.b10.climate_earth.svg +16 -0
- package/AISB/image/aisb.b11.model_efficiency.svg +16 -0
- package/AISB/image/aisb.b12.embodied_ai.svg +16 -0
- package/AISB/image/aisb.b2.agent_systems.svg +16 -0
- package/AISB/image/aisb.b3.self_evolving_rl.svg +16 -0
- package/AISB/image/aisb.b4.lm_reasoning.svg +16 -0
- package/AISB/image/aisb.b5.math_proof.svg +16 -0
- package/AISB/image/aisb.b6.research_process.svg +16 -0
- package/AISB/image/aisb.b7.multimodal_fusion.svg +16 -0
- package/AISB/image/aisb.b8.lifesci_drug.svg +16 -0
- package/AISB/image/aisb.b9.material_science.svg +16 -0
- package/README.md +196 -32
- package/bin/ds.js +924 -66
- package/docs/en/00_QUICK_START.md +195 -18
- package/docs/en/01_SETTINGS_REFERENCE.md +468 -96
- package/docs/en/02_START_RESEARCH_GUIDE.md +26 -5
- package/docs/en/03_QQ_CONNECTOR_GUIDE.md +14 -3
- package/docs/en/04_LINGZHU_CONNECTOR_GUIDE.md +2 -0
- package/docs/en/05_TUI_GUIDE.md +171 -2
- package/docs/en/07_MEMORY_AND_MCP.md +38 -2
- package/docs/en/09_DOCTOR.md +78 -7
- package/docs/en/10_WEIXIN_CONNECTOR_GUIDE.md +38 -1
- package/docs/en/11_LICENSE_AND_RISK.md +4 -0
- package/docs/en/12_GUIDED_WORKFLOW_TOUR.md +15 -0
- package/docs/en/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +9 -0
- package/docs/en/15_CODEX_PROVIDER_SETUP.md +624 -180
- package/docs/en/16_TELEGRAM_CONNECTOR_GUIDE.md +14 -0
- package/docs/en/17_WHATSAPP_CONNECTOR_GUIDE.md +14 -0
- package/docs/en/18_FEISHU_CONNECTOR_GUIDE.md +14 -0
- package/docs/en/21_LOCAL_MODEL_BACKENDS_GUIDE.md +386 -0
- package/docs/en/22_BENCHSTORE_YAML_REFERENCE.md +469 -0
- package/docs/en/23_BENCHSTORE_GITHUB_RELEASES_SPEC.md +316 -0
- package/docs/en/24_CLAUDE_CODE_PROVIDER_SETUP.md +469 -0
- package/docs/en/25_OPENCODE_PROVIDER_SETUP.md +653 -0
- package/docs/en/26_CITATION_AND_ATTRIBUTION.md +119 -0
- package/docs/en/27_KIMI_CODE_PROVIDER_SETUP.md +180 -0
- package/docs/en/28_DISCORD_CONNECTOR_GUIDE.md +61 -0
- package/docs/en/29_SLACK_CONNECTOR_GUIDE.md +60 -0
- package/docs/en/30_SETTINGS_CONTROL_CENTER_GUIDE.md +371 -0
- package/docs/en/{19_LOCAL_BROWSER_AUTH.md → 31_LOCAL_BROWSER_AUTH.md} +1 -1
- package/docs/en/32_WINDOWS_WSL2_DEPLOYMENT_GUIDE.md +273 -0
- package/docs/en/33_WORKSPACE_EXPLORER_QA.md +121 -0
- package/docs/en/91_DEVELOPMENT.md +266 -0
- package/docs/en/99_ACKNOWLEDGEMENTS.md +24 -19
- package/docs/en/README.md +48 -7
- package/docs/images/admin/admin-connectors-health-en.png +0 -0
- package/docs/images/admin/admin-controllers-en.png +0 -0
- package/docs/images/admin/admin-diagnostics-en.png +0 -0
- package/docs/images/admin/admin-errors-en.png +0 -0
- package/docs/images/admin/admin-issues-en.png +0 -0
- package/docs/images/admin/admin-logs-en.png +0 -0
- package/docs/images/admin/admin-quest-detail-en.png +0 -0
- package/docs/images/admin/admin-quests-en.png +0 -0
- package/docs/images/admin/admin-repairs-en.png +0 -0
- package/docs/images/admin/admin-runtime-en.png +0 -0
- package/docs/images/admin/admin-search-en.png +0 -0
- package/docs/images/admin/admin-stats-en.png +0 -0
- package/docs/images/admin/admin-summary-en.png +0 -0
- package/docs/images/connectors/connector-discord-en.png +0 -0
- package/docs/images/connectors/connector-feishu-en.png +0 -0
- package/docs/images/connectors/connector-lingzhu-en.png +0 -0
- package/docs/images/connectors/connector-qq-en.png +0 -0
- package/docs/images/connectors/connector-slack-en.png +0 -0
- package/docs/images/connectors/connector-telegram-en.png +0 -0
- package/docs/images/connectors/connector-weixin-en.png +0 -0
- package/docs/images/connectors/connector-whatsapp-en.png +0 -0
- package/docs/images/settings/settings-baselines-en.png +0 -0
- package/docs/images/settings/settings-config-en.png +0 -0
- package/docs/images/settings/settings-connectors-overview-en.png +0 -0
- package/docs/images/settings/settings-deepxiv-en.png +0 -0
- package/docs/images/settings/settings-mcp-servers-en.png +0 -0
- package/docs/images/settings/settings-plugins-en.png +0 -0
- package/docs/images/settings/settings-runners-en.png +0 -0
- package/docs/zh/00_QUICK_START.md +142 -18
- package/docs/zh/01_SETTINGS_REFERENCE.md +219 -98
- package/docs/zh/02_START_RESEARCH_GUIDE.md +26 -5
- package/docs/zh/05_TUI_GUIDE.md +171 -2
- package/docs/zh/07_MEMORY_AND_MCP.md +29 -2
- package/docs/zh/09_DOCTOR.md +54 -8
- package/docs/zh/10_WEIXIN_CONNECTOR_GUIDE.md +24 -1
- package/docs/zh/11_LICENSE_AND_RISK.md +4 -0
- package/docs/zh/12_GUIDED_WORKFLOW_TOUR.md +15 -0
- package/docs/zh/14_PROMPT_SKILLS_AND_MCP_GUIDE.md +9 -0
- package/docs/zh/15_CODEX_PROVIDER_SETUP.md +552 -181
- package/docs/zh/21_LOCAL_MODEL_BACKENDS_GUIDE.md +384 -0
- package/docs/zh/22_BENCHSTORE_YAML_REFERENCE.md +459 -0
- package/docs/zh/23_BENCHSTORE_GITHUB_RELEASES_SPEC.md +287 -0
- package/docs/zh/23_CLAUDE_RUNNER_GUIDE.md +103 -0
- package/docs/zh/24_CLAUDE_CODE_PROVIDER_SETUP.md +460 -0
- package/docs/zh/25_OPENCODE_PROVIDER_SETUP.md +660 -0
- package/docs/zh/26_CITATION_AND_ATTRIBUTION.md +102 -0
- package/docs/zh/27_KIMI_CODE_PROVIDER_SETUP.md +51 -0
- package/docs/zh/{19_LOCAL_BROWSER_AUTH.md → 31_LOCAL_BROWSER_AUTH.md} +1 -1
- package/docs/zh/32_WINDOWS_WSL2_DEPLOYMENT_GUIDE.md +264 -0
- package/docs/zh/33_WORKSPACE_EXPLORER_QA.md +127 -0
- package/docs/zh/99_ACKNOWLEDGEMENTS.md +23 -19
- package/docs/zh/README.md +33 -7
- package/install.sh +168 -20
- package/package.json +5 -1
- package/pyproject.toml +2 -1
- package/src/deepscientist/__init__.py +1 -1
- package/src/deepscientist/acp/envelope.py +13 -0
- package/src/deepscientist/admin/__init__.py +3 -0
- package/src/deepscientist/admin/charts.py +681 -0
- package/src/deepscientist/admin/logs.py +119 -0
- package/src/deepscientist/admin/repairs.py +217 -0
- package/src/deepscientist/admin/service.py +1310 -0
- package/src/deepscientist/admin/system_info.py +700 -0
- package/src/deepscientist/admin/tasks.py +465 -0
- package/src/deepscientist/admin/tool_metrics.py +600 -0
- package/src/deepscientist/artifact/guidance.py +8 -4
- package/src/deepscientist/artifact/schemas.py +115 -0
- package/src/deepscientist/artifact/service.py +4268 -260
- package/src/deepscientist/bash_exec/monitor.py +30 -3
- package/src/deepscientist/bash_exec/service.py +134 -1
- package/src/deepscientist/benchstore/__init__.py +4 -0
- package/src/deepscientist/benchstore/prompt_builder.py +224 -0
- package/src/deepscientist/benchstore/service.py +1716 -0
- package/src/deepscientist/bridges/connectors.py +8 -2
- package/src/deepscientist/channels/weixin_ilink.py +8 -1
- package/src/deepscientist/cli.py +92 -17
- package/src/deepscientist/codex_cli_compat.py +187 -74
- package/src/deepscientist/config/models.py +82 -11
- package/src/deepscientist/config/service.py +1077 -93
- package/src/deepscientist/connector/weixin_support.py +48 -17
- package/src/deepscientist/daemon/api/handlers.py +827 -235
- package/src/deepscientist/daemon/api/router.py +81 -1
- package/src/deepscientist/daemon/app.py +1512 -85
- package/src/deepscientist/diagnostics/__init__.py +6 -0
- package/src/deepscientist/diagnostics/runner_failures.py +277 -0
- package/src/deepscientist/doctor.py +407 -56
- package/src/deepscientist/evidence_packets.py +590 -0
- package/src/deepscientist/home.py +52 -4
- package/src/deepscientist/kimi_cli_compat.py +50 -0
- package/src/deepscientist/latex_runtime.py +2 -2
- package/src/deepscientist/mcp/context.py +2 -0
- package/src/deepscientist/mcp/schemas.py +114 -0
- package/src/deepscientist/mcp/server.py +1566 -126
- package/src/deepscientist/memory/service.py +203 -16
- package/src/deepscientist/process_control.py +8 -1
- package/src/deepscientist/prompts/builder.py +850 -88
- package/src/deepscientist/quest/__init__.py +2 -2
- package/src/deepscientist/quest/layout.py +12 -1
- package/src/deepscientist/quest/node_traces.py +10 -0
- package/src/deepscientist/quest/service.py +1852 -161
- package/src/deepscientist/quest/stage_views.py +1 -1
- package/src/deepscientist/runners/__init__.py +18 -0
- package/src/deepscientist/runners/base.py +89 -1
- package/src/deepscientist/runners/builtins.py +13 -1
- package/src/deepscientist/runners/claude.py +391 -0
- package/src/deepscientist/runners/codex.py +480 -35
- package/src/deepscientist/runners/codex_telemetry.py +127 -0
- package/src/deepscientist/runners/kimi.py +334 -0
- package/src/deepscientist/runners/metadata.py +68 -0
- package/src/deepscientist/runners/opencode.py +414 -0
- package/src/deepscientist/runners/runtime_overrides.py +100 -0
- package/src/deepscientist/runners/simple_cli.py +538 -0
- package/src/deepscientist/runtime_storage.py +303 -0
- package/src/deepscientist/shared.py +80 -16
- package/src/deepscientist/skills/installer.py +37 -0
- package/src/deepscientist/skills/registry.py +2 -0
- package/src/deepscientist/tinytex.py +2 -2
- package/src/deepscientist/tui.py +10 -3
- package/src/prompts/benchstore/system.md +77 -0
- package/src/prompts/connectors/qq.md +33 -2
- package/src/prompts/connectors/weixin.md +208 -23
- package/src/prompts/contracts/admin_ops.md +74 -0
- package/src/prompts/contracts/admin_ops_knowledge.md +138 -0
- package/src/prompts/contracts/shared_interaction.md +5 -10
- package/src/prompts/start_setup/system.md +422 -0
- package/src/prompts/system.md +411 -304
- package/src/prompts/system_copilot.md +89 -0
- package/src/skills/analysis-campaign/SKILL.md +239 -578
- package/src/skills/analysis-campaign/references/artifact-flow-examples.md +102 -0
- package/src/skills/analysis-campaign/references/boundary-cases.md +98 -0
- package/src/skills/analysis-campaign/references/campaign-checklist-template.md +39 -24
- package/src/skills/analysis-campaign/references/campaign-design.md +26 -10
- package/src/skills/analysis-campaign/references/campaign-plan-template.md +53 -54
- package/src/skills/analysis-campaign/references/operational-guidance.md +97 -0
- package/src/skills/analysis-campaign/references/writing-facing-slice-examples.md +10 -20
- package/src/skills/baseline/SKILL.md +183 -461
- package/src/skills/baseline/references/artifact-flow-examples.md +106 -0
- package/src/skills/baseline/references/artifact-payload-examples.md +1 -1
- package/src/skills/baseline/references/baseline-checklist-template.md +27 -35
- package/src/skills/baseline/references/baseline-plan-template.md +37 -76
- package/src/skills/baseline/references/boundary-cases.md +86 -0
- package/src/skills/baseline/references/codebase-audit-checklist.md +2 -6
- package/src/skills/baseline/references/comparability-contract.md +7 -12
- package/src/skills/baseline/references/operational-guidance.md +56 -0
- package/src/skills/baseline/references/route-selection.md +5 -25
- package/src/skills/decision/SKILL.md +113 -306
- package/src/skills/decision/references/checkpoint-memory-template.md +47 -0
- package/src/skills/decision/references/operational-guidance.md +94 -0
- package/src/skills/decision/references/research-route-criteria.md +7 -8
- package/src/skills/decision/references/strategic-decision-template.md +13 -26
- package/src/skills/experiment/SKILL.md +132 -670
- package/src/skills/experiment/references/execution-playbook.md +374 -0
- package/src/skills/experiment/references/main-experiment-checklist-template.md +26 -2
- package/src/skills/experiment/references/main-experiment-plan-template.md +28 -17
- package/src/skills/experiment/references/operational-guidance.md +108 -0
- package/src/skills/finalize/SKILL.md +62 -0
- package/src/skills/finalize/references/checkpoint-memory-template.md +49 -0
- package/src/skills/finalize/references/resume-packet-template.md +7 -0
- package/src/skills/idea/SKILL.md +228 -15
- package/src/skills/idea/references/controlled-brainstorming-playbook.md +78 -0
- package/src/skills/idea/references/current-board-packet-template.md +61 -0
- package/src/skills/idea/references/high-value-idea-sourcing.md +119 -0
- package/src/skills/idea/references/idea-generation-playbook.md +21 -0
- package/src/skills/idea/references/idea-thinking-flow.md +6 -0
- package/src/skills/idea/references/literature-survey-template.md +3 -0
- package/src/skills/idea/references/objective-contract-template.md +54 -0
- package/src/skills/idea/references/outline-seeding-example.md +56 -0
- package/src/skills/idea/references/pre-idea-draft-template.md +105 -0
- package/src/skills/idea/references/related-work-playbook.md +75 -2
- package/src/skills/idea/references/research-history-playbook.md +114 -0
- package/src/skills/idea/references/selection-gate.md +58 -6
- package/src/skills/intake-audit/SKILL.md +43 -2
- package/src/skills/intake-audit/references/state-audit-template.md +10 -0
- package/src/skills/nature-data/SKILL.md +128 -0
- package/src/skills/nature-data/UPSTREAM_LICENSE.txt +21 -0
- package/src/skills/nature-data/agents/openai.yaml +4 -0
- package/src/skills/nature-data/references/chinese-author-alignment.md +84 -0
- package/src/skills/nature-data/references/fair-metadata-checklist.md +105 -0
- package/src/skills/nature-data/references/policy-principles.md +103 -0
- package/src/skills/nature-data/references/repository-and-identifiers.md +96 -0
- package/src/skills/nature-data/references/source-basis.md +54 -0
- package/src/skills/nature-data/references/statement-patterns.md +153 -0
- package/src/skills/nature-figure/SKILL.md +197 -0
- package/src/skills/nature-figure/UPSTREAM_LICENSE.txt +21 -0
- package/src/skills/nature-figure/agents/openai.yaml +4 -0
- package/src/skills/nature-figure/evals/evals.json +37 -0
- package/src/skills/nature-figure/references/api.md +428 -0
- package/src/skills/nature-figure/references/backend-selection.md +100 -0
- package/src/skills/nature-figure/references/chart-types.md +281 -0
- package/src/skills/nature-figure/references/common-patterns.md +349 -0
- package/src/skills/nature-figure/references/design-theory.md +436 -0
- package/src/skills/nature-figure/references/figure-contract.md +93 -0
- package/src/skills/nature-figure/references/nature-2026-observations.md +112 -0
- package/src/skills/nature-figure/references/qa-contract.md +119 -0
- package/src/skills/nature-figure/references/r-template-index.md +66 -0
- package/src/skills/nature-figure/references/r-workflow.md +161 -0
- package/src/skills/nature-figure/references/tutorials.md +250 -0
- package/src/skills/nature-paper2ppt/SKILL.md +507 -0
- package/src/skills/nature-paper2ppt/UPSTREAM_LICENSE.txt +21 -0
- package/src/skills/nature-paper2ppt/agents/openai.yaml +4 -0
- package/src/skills/nature-polishing/SKILL.md +385 -0
- package/src/skills/nature-polishing/UPSTREAM_LICENSE.txt +21 -0
- package/src/skills/nature-polishing/agents/openai.yaml +4 -0
- package/src/skills/nature-polishing/references/phrasebank-playbook.md +162 -0
- package/src/skills/nature-polishing/references/section-moves.md +240 -0
- package/src/skills/nature-polishing/references/style-guardrails.md +94 -0
- package/src/skills/nature-polishing/references/writing-strategy.md +148 -0
- package/src/skills/optimize/SKILL.md +177 -1568
- package/src/skills/optimize/references/brief-shaping-playbook.md +95 -0
- package/src/skills/optimize/references/candidate-board-template.md +13 -0
- package/src/skills/optimize/references/candidate-ranking-template.md +51 -0
- package/src/skills/optimize/references/codegen-route-playbook.md +50 -0
- package/src/skills/optimize/references/debug-response-template.md +29 -0
- package/src/skills/optimize/references/frontier-review-template.md +32 -0
- package/src/skills/optimize/references/fusion-playbook.md +36 -0
- package/src/skills/optimize/references/method-brief-template.md +73 -0
- package/src/skills/optimize/references/operational-guidance.md +621 -0
- package/src/skills/optimize/references/optimization-memory-template.md +30 -0
- package/src/skills/optimize/references/optimize-checklist-template.md +18 -0
- package/src/skills/optimize/references/plateau-response-playbook.md +28 -0
- package/src/skills/optimize/references/prompt-patterns.md +49 -0
- package/src/skills/paper-outline/SKILL.md +227 -0
- package/src/skills/paper-outline/references/outline-patterns.md +87 -0
- package/src/skills/paper-plot/SKILL.md +79 -0
- package/src/skills/paper-plot/agents/openai.yaml +4 -0
- package/src/skills/paper-plot/references/bar_grouped_hatch.md +96 -0
- package/src/skills/paper-plot/references/bar_paired_delta.md +72 -0
- package/src/skills/paper-plot/references/line_confidence_band.md +75 -0
- package/src/skills/paper-plot/references/line_loss_with_inset.md +65 -0
- package/src/skills/paper-plot/references/line_training_curve.md +44 -0
- package/src/skills/paper-plot/references/radar_dual_series.md +59 -0
- package/src/skills/paper-plot/references/scatter_broken_axis.md +59 -0
- package/src/skills/paper-plot/references/scatter_tsne_cluster.md +72 -0
- package/src/skills/paper-plot/scripts/bar_memevolve.py +109 -0
- package/src/skills/paper-plot/scripts/bar_spice.py +166 -0
- package/src/skills/paper-plot/scripts/line_aime.py +94 -0
- package/src/skills/paper-plot/scripts/line_loss_inset.py +157 -0
- package/src/skills/paper-plot/scripts/line_selfdistill.py +168 -0
- package/src/skills/paper-plot/scripts/radar_dora.py +151 -0
- package/src/skills/paper-plot/scripts/scatter_break.py +169 -0
- package/src/skills/paper-plot/scripts/scatter_tsne.py +133 -0
- package/src/skills/rebuttal/SKILL.md +9 -0
- package/src/skills/references/tool-usage-by-stage.md +438 -0
- package/src/skills/review/SKILL.md +105 -7
- package/src/skills/science/PROVENANCE.md +44 -0
- package/src/skills/science/SKILL.md +137 -0
- package/src/skills/science/references/artifact-science-tool.md +110 -0
- package/src/skills/science/references/claim-type-discipline.md +56 -0
- package/src/skills/science/references/domain-index.md +422 -0
- package/src/skills/science/references/hpc-via-bash-exec.md +42 -0
- package/src/skills/science/references/package-check-playbook.md +64 -0
- package/src/skills/science/references/package-index.min.json +3616 -0
- package/src/skills/science/references/packages/abinit.md +80 -0
- package/src/skills/science/references/packages/acts.md +73 -0
- package/src/skills/science/references/packages/aiida-core.md +80 -0
- package/src/skills/science/references/packages/alamode.md +80 -0
- package/src/skills/science/references/packages/amuse.md +88 -0
- package/src/skills/science/references/packages/anndata.md +88 -0
- package/src/skills/science/references/packages/arbor.md +80 -0
- package/src/skills/science/references/packages/arc.md +73 -0
- package/src/skills/science/references/packages/astropy.md +88 -0
- package/src/skills/science/references/packages/astroquery.md +88 -0
- package/src/skills/science/references/packages/atomate2.md +80 -0
- package/src/skills/science/references/packages/atomsmltr.md +73 -0
- package/src/skills/science/references/packages/awkward.md +73 -0
- package/src/skills/science/references/packages/batman.md +88 -0
- package/src/skills/science/references/packages/biopython.md +88 -0
- package/src/skills/science/references/packages/bloqade.md +73 -0
- package/src/skills/science/references/packages/brian2.md +73 -0
- package/src/skills/science/references/packages/bullet3.md +73 -0
- package/src/skills/science/references/packages/calculix.md +80 -0
- package/src/skills/science/references/packages/cantera.md +73 -0
- package/src/skills/science/references/packages/cavity-md-ipi.md +80 -0
- package/src/skills/science/references/packages/ccdproc.md +88 -0
- package/src/skills/science/references/packages/celerite2.md +88 -0
- package/src/skills/science/references/packages/cellrank.md +73 -0
- package/src/skills/science/references/packages/cesm.md +80 -0
- package/src/skills/science/references/packages/chemicals.md +73 -0
- package/src/skills/science/references/packages/chempy.md +73 -0
- package/src/skills/science/references/packages/cirq.md +73 -0
- package/src/skills/science/references/packages/coffea.md +73 -0
- package/src/skills/science/references/packages/cp2k.md +88 -0
- package/src/skills/science/references/packages/custodian.md +80 -0
- package/src/skills/science/references/packages/dart.md +73 -0
- package/src/skills/science/references/packages/datamol.md +88 -0
- package/src/skills/science/references/packages/dd4hep.md +73 -0
- package/src/skills/science/references/packages/dealii.md +80 -0
- package/src/skills/science/references/packages/deepchem.md +88 -0
- package/src/skills/science/references/packages/delphes.md +73 -0
- package/src/skills/science/references/packages/devito.md +80 -0
- package/src/skills/science/references/packages/dftb.md +88 -0
- package/src/skills/science/references/packages/dftd4.md +88 -0
- package/src/skills/science/references/packages/dftk-jl.md +80 -0
- package/src/skills/science/references/packages/dolfinx.md +80 -0
- package/src/skills/science/references/packages/drake.md +73 -0
- package/src/skills/science/references/packages/dumux.md +73 -0
- package/src/skills/science/references/packages/elk.md +80 -0
- package/src/skills/science/references/packages/elmerfem.md +80 -0
- package/src/skills/science/references/packages/enzo-e.md +88 -0
- package/src/skills/science/references/packages/espresso.md +80 -0
- package/src/skills/science/references/packages/exoplanet.md +88 -0
- package/src/skills/science/references/packages/fairroot.md +73 -0
- package/src/skills/science/references/packages/fbpic.md +80 -0
- package/src/skills/science/references/packages/fdtdbath-meep.md +80 -0
- package/src/skills/science/references/packages/geant4.md +73 -0
- package/src/skills/science/references/packages/geosx.md +80 -0
- package/src/skills/science/references/packages/gprmax.md +80 -0
- package/src/skills/science/references/packages/gromacs.md +80 -0
- package/src/skills/science/references/packages/gwaslab.md +73 -0
- package/src/skills/science/references/packages/gz-sim.md +73 -0
- package/src/skills/science/references/packages/hail.md +88 -0
- package/src/skills/science/references/packages/hiphive.md +80 -0
- package/src/skills/science/references/packages/hoomd-blue.md +80 -0
- package/src/skills/science/references/packages/itensor.md +73 -0
- package/src/skills/science/references/packages/itensors-jl.md +73 -0
- package/src/skills/science/references/packages/jdftx.md +73 -0
- package/src/skills/science/references/packages/jobflow.md +80 -0
- package/src/skills/science/references/packages/kadanoffbaym-jl.md +73 -0
- package/src/skills/science/references/packages/kite.md +80 -0
- package/src/skills/science/references/packages/kratos.md +80 -0
- package/src/skills/science/references/packages/kwant.md +73 -0
- package/src/skills/science/references/packages/lammps.md +80 -0
- package/src/skills/science/references/packages/lightkurve.md +88 -0
- package/src/skills/science/references/packages/limix.md +73 -0
- package/src/skills/science/references/packages/maxwelllink.md +80 -0
- package/src/skills/science/references/packages/mcdc.md +73 -0
- package/src/skills/science/references/packages/meep.md +80 -0
- package/src/skills/science/references/packages/mfem.md +80 -0
- package/src/skills/science/references/packages/mitgcm.md +73 -0
- package/src/skills/science/references/packages/modflow6.md +73 -0
- package/src/skills/science/references/packages/molecool.md +73 -0
- package/src/skills/science/references/packages/mom6.md +73 -0
- package/src/skills/science/references/packages/moose.md +80 -0
- package/src/skills/science/references/packages/mpas-model.md +73 -0
- package/src/skills/science/references/packages/mujoco.md +73 -0
- package/src/skills/science/references/packages/mumax3.md +73 -0
- package/src/skills/science/references/packages/nekrs.md +80 -0
- package/src/skills/science/references/packages/nessi.md +73 -0
- package/src/skills/science/references/packages/nest-simulator.md +73 -0
- package/src/skills/science/references/packages/netket.md +73 -0
- package/src/skills/science/references/packages/neuron.md +73 -0
- package/src/skills/science/references/packages/nextflow.md +88 -0
- package/src/skills/science/references/packages/nwchem.md +88 -0
- package/src/skills/science/references/packages/openbabel.md +88 -0
- package/src/skills/science/references/packages/openems.md +80 -0
- package/src/skills/science/references/packages/openff-toolkit.md +88 -0
- package/src/skills/science/references/packages/openfoam-dev.md +80 -0
- package/src/skills/science/references/packages/openmc.md +73 -0
- package/src/skills/science/references/packages/openmm.md +80 -0
- package/src/skills/science/references/packages/openmoc.md +73 -0
- package/src/skills/science/references/packages/openmx.md +80 -0
- package/src/skills/science/references/packages/opensees.md +80 -0
- package/src/skills/science/references/packages/opensn.md +80 -0
- package/src/skills/science/references/packages/opm-simulators.md +73 -0
- package/src/skills/science/references/packages/oqupy.md +73 -0
- package/src/skills/science/references/packages/packmol.md +80 -0
- package/src/skills/science/references/packages/palabos.md +80 -0
- package/src/skills/science/references/packages/parflow.md +80 -0
- package/src/skills/science/references/packages/pennylane.md +88 -0
- package/src/skills/science/references/packages/perceval.md +73 -0
- package/src/skills/science/references/packages/phono3py.md +73 -0
- package/src/skills/science/references/packages/phonopy.md +73 -0
- package/src/skills/science/references/packages/photutils.md +88 -0
- package/src/skills/science/references/packages/picongpu.md +80 -0
- package/src/skills/science/references/packages/plink-ng.md +88 -0
- package/src/skills/science/references/packages/precice.md +73 -0
- package/src/skills/science/references/packages/psc.md +80 -0
- package/src/skills/science/references/packages/psi4.md +88 -0
- package/src/skills/science/references/packages/pybinding.md +73 -0
- package/src/skills/science/references/packages/pyfr.md +80 -0
- package/src/skills/science/references/packages/pyhf.md +73 -0
- package/src/skills/science/references/packages/pyiron_base.md +80 -0
- package/src/skills/science/references/packages/pylcp.md +73 -0
- package/src/skills/science/references/packages/pylith.md +80 -0
- package/src/skills/science/references/packages/pynbody.md +88 -0
- package/src/skills/science/references/packages/pysam.md +88 -0
- package/src/skills/science/references/packages/pyscf.md +88 -0
- package/src/skills/science/references/packages/q-e.md +73 -0
- package/src/skills/science/references/packages/qibo.md +73 -0
- package/src/skills/science/references/packages/qiskit.md +73 -0
- package/src/skills/science/references/packages/quantica-jl.md +73 -0
- package/src/skills/science/references/packages/quantumoptics-jl.md +73 -0
- package/src/skills/science/references/packages/quimb.md +73 -0
- package/src/skills/science/references/packages/qulacs.md +73 -0
- package/src/skills/science/references/packages/qutip.md +73 -0
- package/src/skills/science/references/packages/rdkit.md +88 -0
- package/src/skills/science/references/packages/rmg-py.md +73 -0
- package/src/skills/science/references/packages/root.md +73 -0
- package/src/skills/science/references/packages/scanpy.md +88 -0
- package/src/skills/science/references/packages/scikit-allel.md +88 -0
- package/src/skills/science/references/packages/scikit-bio.md +88 -0
- package/src/skills/science/references/packages/scqubits.md +73 -0
- package/src/skills/science/references/packages/scuff-em.md +80 -0
- package/src/skills/science/references/packages/scvi-tools.md +73 -0
- package/src/skills/science/references/packages/seissol.md +73 -0
- package/src/skills/science/references/packages/sfepy.md +80 -0
- package/src/skills/science/references/packages/sisl.md +73 -0
- package/src/skills/science/references/packages/smilei.md +80 -0
- package/src/skills/science/references/packages/snakemake.md +88 -0
- package/src/skills/science/references/packages/specfem3d-globe.md +80 -0
- package/src/skills/science/references/packages/specutils.md +88 -0
- package/src/skills/science/references/packages/spglib.md +80 -0
- package/src/skills/science/references/packages/squidpy.md +88 -0
- package/src/skills/science/references/packages/starry.md +88 -0
- package/src/skills/science/references/packages/strawberryfields.md +73 -0
- package/src/skills/science/references/packages/su2.md +80 -0
- package/src/skills/science/references/packages/sunny-jl.md +73 -0
- package/src/skills/science/references/packages/sw4.md +73 -0
- package/src/skills/science/references/packages/swift.md +88 -0
- package/src/skills/science/references/packages/tdnegf.md +73 -0
- package/src/skills/science/references/packages/tenpy.md +73 -0
- package/src/skills/science/references/packages/thermo.md +73 -0
- package/src/skills/science/references/packages/tkwant.md +73 -0
- package/src/skills/science/references/packages/tvb-root.md +73 -0
- package/src/skills/science/references/packages/uproot5.md +73 -0
- package/src/skills/science/references/packages/vampire.md +80 -0
- package/src/skills/science/references/packages/wannier_tools.md +73 -0
- package/src/skills/science/references/packages/warpx.md +80 -0
- package/src/skills/science/references/packages/wrf.md +73 -0
- package/src/skills/science/references/packages/xtb.md +88 -0
- package/src/skills/science/references/packages/yt.md +73 -0
- package/src/skills/science/references/science-task-brief-template.md +71 -0
- package/src/skills/scout/SKILL.md +83 -425
- package/src/skills/scout/references/literature-scout-template.md +5 -24
- package/src/skills/scout/references/operational-guidance.md +191 -0
- package/src/skills/scout/references/paper-triage-playbook.md +11 -35
- package/src/skills/write/SKILL.md +744 -1246
- package/src/skills/write/references/experiments_analysis_patterns.md +129 -0
- package/src/skills/write/references/oral_package_patterns.md +252 -0
- package/src/skills/write/references/oral_writing_principles.md +291 -0
- package/src/skills/write/references/section_rewrite_checklist.md +234 -0
- package/src/tui/dist/app/AppContainer.js +1314 -27
- package/src/tui/dist/components/Composer.js +26 -1
- package/src/tui/dist/components/ConfigScreen.js +2 -1
- package/src/tui/dist/components/InputPrompt.js +25 -9
- package/src/tui/dist/components/MainContent.js +18 -3
- package/src/tui/dist/components/QuestScreen.js +3 -2
- package/src/tui/dist/components/UtilityScreen.js +37 -0
- package/src/tui/dist/hooks/useSafeInput.js +10 -0
- package/src/tui/dist/index.js +13 -1
- package/src/tui/dist/layouts/DefaultAppLayout.js +11 -8
- package/src/tui/dist/lib/api.js +89 -1
- package/src/tui/package.json +1 -1
- package/src/ui/dist/assets/{AnalysisPlugin-DnSm0GZn.js → AnalysisPlugin-CA94NGmI.js} +1 -1
- package/src/ui/dist/assets/CliPlugin-DHBzphZU.js +79 -0
- package/src/ui/dist/assets/CodeEditorPlugin-BOFwD2rn.js +2 -0
- package/src/ui/dist/assets/{CodeViewerPlugin-itb0tltR.js → CodeViewerPlugin-CqDpgjik.js} +4 -4
- package/src/ui/dist/assets/{DocViewerPlugin-DqKkiCI6.js → DocViewerPlugin-UDBgt8-4.js} +3 -3
- package/src/ui/dist/assets/GitCommitViewerPlugin-BmHtZ0bZ.js +6 -0
- package/src/ui/dist/assets/{GitDiffViewerPlugin-DxL2ezFG.js → GitDiffViewerPlugin-CAxjNorQ.js} +2 -2
- package/src/ui/dist/assets/{GitSnapshotViewer-B_RQm1YZ.js → GitSnapshotViewer-CweA6VON.js} +2 -2
- package/src/ui/dist/assets/{ImageViewerPlugin-tHqlXY3n.js → ImageViewerPlugin-C8wHGvGN.js} +5 -5
- package/src/ui/dist/assets/LabPlugin-COyyLUol.js +32 -0
- package/src/ui/dist/assets/{LatexPlugin-B495DTXC.js → LatexPlugin-BQjAaA5J.js} +4 -4
- package/src/ui/dist/assets/{MarkdownViewerPlugin-DG28-61B.js → MarkdownViewerPlugin-Dy1NE2dI.js} +3 -3
- package/src/ui/dist/assets/{MarketplacePlugin-BiOGT-Kj.js → MarketplacePlugin-DMIZtEJ2.js} +2 -2
- package/src/ui/dist/assets/NotebookEditor-CFHMq_Qt.js +91 -0
- package/src/ui/dist/assets/{NotebookEditor-CVsj8h_T.js → NotebookEditor-WFyd8Ybt.js} +23 -23
- package/src/ui/dist/assets/{PdfLoader-CASDQmxJ.js → PdfLoader-CLE5u5TS.js} +3 -3
- package/src/ui/dist/assets/{PdfMarkdownPlugin-BFhwoKsY.js → PdfMarkdownPlugin-_iNK_H83.js} +1 -1
- package/src/ui/dist/assets/PdfViewerPlugin-DgWsbInT.js +22 -0
- package/src/ui/dist/assets/SearchPlugin-DrZmn5iw.js +11 -0
- package/src/ui/dist/assets/{TextViewerPlugin-CB4DYfWO.js → TextViewerPlugin-D1-T3aC7.js} +4 -4
- package/src/ui/dist/assets/branding/runner-claude.svg +107 -0
- package/src/ui/dist/assets/branding/runner-codex.svg +10 -0
- package/src/ui/dist/assets/branding/runner-kimi.svg +14 -0
- package/src/ui/dist/assets/branding/runner-opencode.svg +7 -0
- package/src/ui/dist/assets/cli-store-CoZ-x5Ip.js +1 -0
- package/src/ui/dist/assets/{code-DLC6G24T.js → code-DbsmSd3Y.js} +1 -1
- package/src/ui/dist/assets/file-diff-panel-DsvyRz47.js +1 -0
- package/src/ui/dist/assets/{wrap-text-CwMn-iqb.js → file-jump-queue-DeQBikaw.js} +3 -3
- package/src/ui/dist/assets/{file-socket-Cu4Qln7Y.js → file-socket-DA5XIx88.js} +1 -1
- package/src/ui/dist/assets/fonts/ds-fonts.css +50 -4
- package/src/ui/dist/assets/images/deepxiv/register-guide.png +0 -0
- package/src/ui/dist/assets/index-39vY9LmZ.js +1 -0
- package/src/ui/dist/assets/{index-wQ7RIIRd.js → index-BsO46tJA.js} +1 -1
- package/src/ui/dist/assets/index-CHzJ2xtB.js +3530 -0
- package/src/ui/dist/assets/index-DH-zxoZ3.css +33 -0
- package/src/ui/dist/assets/{plugin-notebook-HbW2K-1c.js → plugin-notebook-JRhysCqj.js} +2 -2
- package/src/ui/dist/assets/{project-sync-CsX08Qno.js → project-sync-DPmWKmKD.js} +1 -1
- package/src/ui/dist/assets/{zoom-out-R-GWEhzS.js → zoom-out-DAukFWen.js} +3 -3
- package/src/ui/dist/index.html +3 -3
- package/src/skills/analysis-campaign/references/artifact-orchestration.md +0 -58
- package/src/skills/baseline/references/memory-playbook.md +0 -40
- package/src/skills/baseline/references/publishable-baseline-package.md +0 -30
- package/src/skills/write/references/outline-evidence-contract-example.md +0 -107
- package/src/skills/write/references/paper-experiment-matrix-template.md +0 -131
- package/src/skills/write/references/paper-section-playbook.md +0 -64
- package/src/skills/write/references/reviewer-first-writing.md +0 -64
- package/src/skills/write/references/revision-checklist.md +0 -70
- package/src/skills/write/references/section-contracts.md +0 -82
- package/src/skills/write/references/sentence-level-proofing.md +0 -49
- package/src/ui/dist/assets/AiManusChatView-COFACy7V.js +0 -204
- package/src/ui/dist/assets/CliPlugin-CvwCmDQ5.js +0 -109
- package/src/ui/dist/assets/CodeEditorPlugin-cOqSa0xq.js +0 -2
- package/src/ui/dist/assets/GitCommitViewerPlugin-DVgNHBCS.js +0 -1
- package/src/ui/dist/assets/LabCopilotPanel-ClMbq5Yu.js +0 -14
- package/src/ui/dist/assets/LabPlugin-L_SuE8ow.js +0 -22
- package/src/ui/dist/assets/NotebookEditor-C-4Kt1p9.js +0 -81
- package/src/ui/dist/assets/PdfViewerPlugin-DcOzU9vd.js +0 -17
- package/src/ui/dist/assets/SearchPlugin-CHj7M58O.js +0 -16
- package/src/ui/dist/assets/VNCViewer-CjlbyCB3.js +0 -11
- package/src/ui/dist/assets/bot-CFkZY-JP.js +0 -6
- package/src/ui/dist/assets/chevron-up-Dq5ofbht.js +0 -6
- package/src/ui/dist/assets/file-content-Dv4LoZec.js +0 -1
- package/src/ui/dist/assets/file-diff-panel-Denq-lC3.js +0 -1
- package/src/ui/dist/assets/file-jump-queue-DA-SdG__.js +0 -1
- package/src/ui/dist/assets/git-commit-horizontal-BUh6G52n.js +0 -6
- package/src/ui/dist/assets/image-B9HUUddG.js +0 -6
- package/src/ui/dist/assets/index-B2B1sg-M.js +0 -1
- package/src/ui/dist/assets/index-Cgla8biy.css +0 -33
- package/src/ui/dist/assets/index-DRyx7vAc.js +0 -1
- package/src/ui/dist/assets/index-Gbl53BNp.js +0 -2496
- package/src/ui/dist/assets/pdf-effect-queue-ZtnHFCAi.js +0 -6
- package/src/ui/dist/assets/popover-DL6h35vr.js +0 -1
- package/src/ui/dist/assets/select-DvmXt1yY.js +0 -11
- package/src/ui/dist/assets/sigma-7jpXazui.js +0 -6
- package/src/ui/dist/assets/trash-xA7kFt8i.js +0 -11
- package/src/ui/dist/assets/useCliAccess-DsMwDjOp.js +0 -1
- package/src/ui/dist/assets/useFileDiffOverlay-FuhcnKiw.js +0 -1
|
@@ -2,8 +2,13 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import argparse
|
|
4
4
|
from collections import deque
|
|
5
|
+
import json
|
|
5
6
|
from pathlib import Path
|
|
7
|
+
import shlex
|
|
8
|
+
import sys
|
|
6
9
|
from typing import Any
|
|
10
|
+
from urllib import error as urllib_error
|
|
11
|
+
from urllib import request as urllib_request
|
|
7
12
|
|
|
8
13
|
from mcp.server.fastmcp import FastMCP
|
|
9
14
|
from mcp.types import ToolAnnotations
|
|
@@ -11,21 +16,183 @@ from mcp.types import ToolAnnotations
|
|
|
11
16
|
from ..artifact import ArtifactService
|
|
12
17
|
from ..artifact.metrics import MetricContractValidationError
|
|
13
18
|
from ..bash_exec import BashExecService
|
|
19
|
+
from ..evidence_packets import cached_compact_mcp_tool_result, compact_mcp_tool_result
|
|
14
20
|
from ..memory import MemoryService
|
|
15
21
|
from ..quest import QuestService
|
|
22
|
+
from ..shared import read_json
|
|
16
23
|
from .context import McpContext
|
|
24
|
+
from .schemas import MetricContractPayload, PrimaryMetricPayload, SupplementaryBaselinePayload
|
|
17
25
|
|
|
18
26
|
DEFAULT_INLINE_BASH_LOG_LINE_LIMIT = 2000
|
|
19
27
|
DEFAULT_INLINE_BASH_LOG_HEAD_LINES = 500
|
|
20
28
|
DEFAULT_INLINE_BASH_LOG_TAIL_LINES = 1500
|
|
21
29
|
DEFAULT_INLINE_BASH_LOG_WINDOW_LINES = 200
|
|
22
30
|
MAX_INLINE_BASH_LOG_WINDOW_LINES = 2000
|
|
31
|
+
DEFAULT_BASH_EXEC_AWAIT_WAIT_TIMEOUT_SECONDS = 1800
|
|
32
|
+
BASH_EXEC_TERMINAL_STATUSES = {"completed", "failed", "terminated"}
|
|
23
33
|
INTERACTION_WATCHDOG_TOOL_CALL_THRESHOLD = 25
|
|
24
34
|
INTERACTION_WATCHDOG_SILENCE_THRESHOLD_SECONDS = 30 * 60
|
|
25
35
|
LONG_BASH_LOG_HINT = (
|
|
26
36
|
"Use `bash_exec(mode='read', id=..., start=..., tail=...)` to inspect a specific log window, "
|
|
27
37
|
"or `bash_exec(mode='read', id=..., tail=...)` to inspect the latest rendered lines."
|
|
28
38
|
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _attach_bash_log_truncation_metadata(payload: dict[str, Any]) -> dict[str, Any]:
|
|
42
|
+
result = dict(payload)
|
|
43
|
+
|
|
44
|
+
log_line_count = result.get("log_line_count")
|
|
45
|
+
latest_seq = result.get("latest_seq")
|
|
46
|
+
tail_start_seq = result.get("tail_start_seq")
|
|
47
|
+
line_start = result.get("line_start")
|
|
48
|
+
line_end = result.get("line_end")
|
|
49
|
+
|
|
50
|
+
def _as_int(value: object) -> int | None:
|
|
51
|
+
if isinstance(value, bool):
|
|
52
|
+
return None
|
|
53
|
+
if isinstance(value, int):
|
|
54
|
+
return value
|
|
55
|
+
try:
|
|
56
|
+
return int(str(value))
|
|
57
|
+
except (TypeError, ValueError):
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
total_lines = _as_int(log_line_count) or 0
|
|
61
|
+
latest_seq_value = _as_int(latest_seq)
|
|
62
|
+
tail_start_seq_value = _as_int(tail_start_seq)
|
|
63
|
+
line_start_value = _as_int(line_start)
|
|
64
|
+
line_end_value = _as_int(line_end)
|
|
65
|
+
|
|
66
|
+
if result.get("log_truncated") is True:
|
|
67
|
+
head_lines = _as_int(result.get("log_preview_head_lines")) or 0
|
|
68
|
+
tail_lines = _as_int(result.get("log_preview_tail_lines")) or 0
|
|
69
|
+
omitted_lines = _as_int(result.get("log_preview_omitted_lines")) or max(total_lines - head_lines - tail_lines, 0)
|
|
70
|
+
after_preview_lines = tail_lines
|
|
71
|
+
before_preview_lines = head_lines
|
|
72
|
+
result["log_is_partial"] = True
|
|
73
|
+
result["log_visible_line_start"] = 1 if total_lines else 0
|
|
74
|
+
result["log_visible_line_end"] = total_lines if total_lines and total_lines <= head_lines + tail_lines else head_lines + tail_lines
|
|
75
|
+
result["log_lines_before_window"] = 0
|
|
76
|
+
result["log_lines_after_window"] = max(total_lines - tail_lines, 0) if total_lines else 0
|
|
77
|
+
result["seq_has_more_before"] = False
|
|
78
|
+
result["seq_has_more_after"] = omitted_lines > 0
|
|
79
|
+
result["seqs_before_window"] = 0
|
|
80
|
+
result["seqs_after_window"] = omitted_lines
|
|
81
|
+
result["log_truncation_notice"] = (
|
|
82
|
+
"This log payload is truncated to a preview window rather than the full output. "
|
|
83
|
+
f"It shows the first {head_lines} line(s) and the last {tail_lines} line(s), omitting {omitted_lines} middle line(s). "
|
|
84
|
+
"Do not treat this preview as exhaustive evidence. "
|
|
85
|
+
"Use bash_exec(mode='read', id=..., start=..., tail=...) for a specific line window, "
|
|
86
|
+
"or bash_exec(mode='read', id=..., tail_limit=..., before_seq=..., after_seq=...) for seq-based continuation."
|
|
87
|
+
)
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
if result.get("log_windowed") is True:
|
|
91
|
+
if line_start_value is None:
|
|
92
|
+
line_start_value = 1 if total_lines else 0
|
|
93
|
+
if line_end_value is None:
|
|
94
|
+
line_end_value = line_start_value - 1 if line_start_value else 0
|
|
95
|
+
lines_before = max((line_start_value - 1) if line_start_value else 0, 0)
|
|
96
|
+
lines_after = max(total_lines - max(line_end_value or 0, 0), 0)
|
|
97
|
+
result["log_is_partial"] = bool(result.get("has_more_before")) or bool(result.get("has_more_after"))
|
|
98
|
+
result["log_lines_before_window"] = lines_before
|
|
99
|
+
result["log_lines_after_window"] = lines_after
|
|
100
|
+
result["log_visible_line_start"] = line_start_value
|
|
101
|
+
result["log_visible_line_end"] = line_end_value
|
|
102
|
+
|
|
103
|
+
if tail_start_seq_value is not None:
|
|
104
|
+
seq_window_start = tail_start_seq_value
|
|
105
|
+
seq_window_end = (
|
|
106
|
+
tail_start_seq_value + (_as_int(result.get("returned_line_count")) or 0) - 1
|
|
107
|
+
if (_as_int(result.get("returned_line_count")) or 0) > 0
|
|
108
|
+
else tail_start_seq_value - 1
|
|
109
|
+
)
|
|
110
|
+
else:
|
|
111
|
+
seq_window_start = line_start_value
|
|
112
|
+
seq_window_end = line_end_value
|
|
113
|
+
seqs_before = max((seq_window_start or 0) - 1, 0)
|
|
114
|
+
seqs_after = (
|
|
115
|
+
max(latest_seq_value - max(seq_window_end or 0, 0), 0)
|
|
116
|
+
if latest_seq_value is not None
|
|
117
|
+
else lines_after
|
|
118
|
+
)
|
|
119
|
+
result["seq_window_start"] = seq_window_start
|
|
120
|
+
result["seq_window_end"] = seq_window_end
|
|
121
|
+
result["seq_has_more_before"] = seqs_before > 0
|
|
122
|
+
result["seq_has_more_after"] = seqs_after > 0
|
|
123
|
+
result["seqs_before_window"] = seqs_before
|
|
124
|
+
result["seqs_after_window"] = seqs_after
|
|
125
|
+
|
|
126
|
+
if result["log_is_partial"]:
|
|
127
|
+
result["log_truncation_notice"] = (
|
|
128
|
+
"This log payload is only a partial window, not the full output. "
|
|
129
|
+
f"It currently covers lines {line_start_value} to {line_end_value} out of {total_lines}, "
|
|
130
|
+
f"with {lines_before} line(s) before and {lines_after} line(s) after this window. "
|
|
131
|
+
"If you need adjacent output, continue with bash_exec(mode='read', id=..., start=..., tail=...) "
|
|
132
|
+
"or use the seq-based before_seq / after_seq parameters."
|
|
133
|
+
)
|
|
134
|
+
return result
|
|
135
|
+
|
|
136
|
+
if total_lines > 0:
|
|
137
|
+
result["log_is_partial"] = False
|
|
138
|
+
result["log_lines_before_window"] = 0
|
|
139
|
+
result["log_lines_after_window"] = 0
|
|
140
|
+
if latest_seq_value is not None:
|
|
141
|
+
result["seq_has_more_before"] = False
|
|
142
|
+
result["seq_has_more_after"] = False
|
|
143
|
+
result["seqs_before_window"] = 0
|
|
144
|
+
result["seqs_after_window"] = 0
|
|
145
|
+
result["seq_window_start"] = 1
|
|
146
|
+
result["seq_window_end"] = latest_seq_value
|
|
147
|
+
return result
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _normalize_positive_timeout_seconds(value: Any, *, field_name: str) -> int | None:
|
|
151
|
+
if value is None or value == "":
|
|
152
|
+
return None
|
|
153
|
+
if isinstance(value, bool):
|
|
154
|
+
raise ValueError(f"{field_name} must be a positive integer.")
|
|
155
|
+
try:
|
|
156
|
+
normalized = int(value)
|
|
157
|
+
except (TypeError, ValueError) as exc:
|
|
158
|
+
raise ValueError(f"{field_name} must be a positive integer.") from exc
|
|
159
|
+
if normalized <= 0:
|
|
160
|
+
raise ValueError(f"{field_name} must be a positive integer.")
|
|
161
|
+
return normalized
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _build_bash_exec_wait_notice(
|
|
165
|
+
*,
|
|
166
|
+
bash_id: str,
|
|
167
|
+
wait_timeout_seconds: int,
|
|
168
|
+
status: str,
|
|
169
|
+
) -> dict[str, Any]:
|
|
170
|
+
suggested_poll_interval_seconds = DEFAULT_BASH_EXEC_AWAIT_WAIT_TIMEOUT_SECONDS
|
|
171
|
+
suggested_sleep_timeout = suggested_poll_interval_seconds + 60
|
|
172
|
+
return {
|
|
173
|
+
"wait_timed_out": True,
|
|
174
|
+
"still_running": status in {"running", "terminating"},
|
|
175
|
+
"wait_timeout_seconds": wait_timeout_seconds,
|
|
176
|
+
"suggested_poll_interval_seconds": suggested_poll_interval_seconds,
|
|
177
|
+
"suggested_read_command": f"bash_exec(mode='read', id='{bash_id}')",
|
|
178
|
+
"suggested_await_command": (
|
|
179
|
+
f"bash_exec(mode='await', id='{bash_id}', "
|
|
180
|
+
f"wait_timeout_seconds={suggested_poll_interval_seconds})"
|
|
181
|
+
),
|
|
182
|
+
"suggested_sleep_command": (
|
|
183
|
+
f"bash_exec(command='sleep {suggested_poll_interval_seconds}', mode='await', "
|
|
184
|
+
f"timeout_seconds={suggested_sleep_timeout})"
|
|
185
|
+
),
|
|
186
|
+
"long_wait_notice": (
|
|
187
|
+
"This managed bash_exec session is still running, so the bounded await window ended without final completion. "
|
|
188
|
+
f"Read the saved log with bash_exec(mode='read', id='{bash_id}') and check again in about "
|
|
189
|
+
f"{suggested_poll_interval_seconds} seconds. Prefer "
|
|
190
|
+
f"bash_exec(mode='await', id='{bash_id}', wait_timeout_seconds={suggested_poll_interval_seconds}) "
|
|
191
|
+
"for the next bounded wait on this managed session; if you only need wall-clock waiting between checks, "
|
|
192
|
+
f"you may use bash_exec(command='sleep {suggested_poll_interval_seconds}', mode='await', "
|
|
193
|
+
f"timeout_seconds={suggested_sleep_timeout}) before reading the log again."
|
|
194
|
+
),
|
|
195
|
+
}
|
|
29
196
|
ARTIFACT_STATE_CHANGE_WATCHDOG_NOTES = {
|
|
30
197
|
"confirm_baseline": (
|
|
31
198
|
"Baseline confirmation changed durable quest state and this tool does not send a user-visible "
|
|
@@ -39,6 +206,10 @@ ARTIFACT_STATE_CHANGE_WATCHDOG_NOTES = {
|
|
|
39
206
|
"Paper outline state changed durably and this tool does not send a user-visible summary on its own. "
|
|
40
207
|
"Send one concise artifact.interact(...) update now."
|
|
41
208
|
),
|
|
209
|
+
"compile_outline_to_writing_plan": (
|
|
210
|
+
"Paper writing plan state changed durably and this tool does not send a user-visible summary on its own. "
|
|
211
|
+
"Send one concise artifact.interact(...) update now."
|
|
212
|
+
),
|
|
42
213
|
"publish_baseline": (
|
|
43
214
|
"Baseline publication changed durable state and this tool does not send a user-visible summary "
|
|
44
215
|
"on its own. Send one concise artifact.interact(...) update now."
|
|
@@ -53,6 +224,85 @@ ARTIFACT_STATE_CHANGE_WATCHDOG_NOTES = {
|
|
|
53
224
|
"received an equivalent completion summary."
|
|
54
225
|
),
|
|
55
226
|
}
|
|
227
|
+
START_SETUP_FORM_FIELDS: tuple[str, ...] = (
|
|
228
|
+
"title",
|
|
229
|
+
"goal",
|
|
230
|
+
"baseline_id",
|
|
231
|
+
"baseline_variant_id",
|
|
232
|
+
"baseline_source_mode",
|
|
233
|
+
"execution_start_mode",
|
|
234
|
+
"baseline_acceptance_target",
|
|
235
|
+
"baseline_urls",
|
|
236
|
+
"paper_urls",
|
|
237
|
+
"runtime_constraints",
|
|
238
|
+
"objectives",
|
|
239
|
+
"need_research_paper",
|
|
240
|
+
"research_intensity",
|
|
241
|
+
"decision_policy",
|
|
242
|
+
"launch_mode",
|
|
243
|
+
"standard_profile",
|
|
244
|
+
"custom_profile",
|
|
245
|
+
"review_followup_policy",
|
|
246
|
+
"baseline_execution_policy",
|
|
247
|
+
"manuscript_edit_mode",
|
|
248
|
+
"entry_state_summary",
|
|
249
|
+
"review_summary",
|
|
250
|
+
"review_materials",
|
|
251
|
+
"custom_brief",
|
|
252
|
+
"user_language",
|
|
253
|
+
)
|
|
254
|
+
START_SETUP_SESSION_FIELDS: tuple[str, ...] = (
|
|
255
|
+
"fit_assessment",
|
|
256
|
+
"recommended_workspace_mode",
|
|
257
|
+
"launch_readiness",
|
|
258
|
+
"missing_confirmations",
|
|
259
|
+
"preview_plan",
|
|
260
|
+
"materials_summary",
|
|
261
|
+
"copilot_handoff",
|
|
262
|
+
"science_task",
|
|
263
|
+
"science_task_brief",
|
|
264
|
+
"science_package_cards",
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _split_nested_start_setup_payload(payload: dict[str, Any] | None) -> tuple[dict[str, Any] | None, dict[str, Any] | None]:
|
|
269
|
+
if not isinstance(payload, dict):
|
|
270
|
+
return None, None
|
|
271
|
+
form_patch = payload.get("form_patch") if isinstance(payload.get("form_patch"), dict) else None
|
|
272
|
+
session_patch = payload.get("session_patch") if isinstance(payload.get("session_patch"), dict) else None
|
|
273
|
+
suggested_form = payload.get("suggested_form") if isinstance(payload.get("suggested_form"), dict) else None
|
|
274
|
+
if isinstance(suggested_form, dict):
|
|
275
|
+
if form_patch is None and isinstance(suggested_form.get("form_patch"), dict):
|
|
276
|
+
form_patch = suggested_form.get("form_patch")
|
|
277
|
+
if session_patch is None and isinstance(suggested_form.get("session_patch"), dict):
|
|
278
|
+
session_patch = suggested_form.get("session_patch")
|
|
279
|
+
return form_patch, session_patch
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def _normalize_bash_exec_command_input(raw_command: Any) -> str:
|
|
283
|
+
if isinstance(raw_command, str):
|
|
284
|
+
return raw_command
|
|
285
|
+
if isinstance(raw_command, (list, tuple)):
|
|
286
|
+
items = [str(item).strip() for item in raw_command if str(item).strip()]
|
|
287
|
+
if not items:
|
|
288
|
+
return ""
|
|
289
|
+
if len(items) == 1:
|
|
290
|
+
return items[0]
|
|
291
|
+
return shlex.join(items)
|
|
292
|
+
return str(raw_command or "")
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
def _normalize_bash_exec_command_input(raw_command: Any) -> str:
|
|
296
|
+
if isinstance(raw_command, str):
|
|
297
|
+
return raw_command
|
|
298
|
+
if isinstance(raw_command, (list, tuple)):
|
|
299
|
+
items = [str(item).strip() for item in raw_command if str(item).strip()]
|
|
300
|
+
if not items:
|
|
301
|
+
return ""
|
|
302
|
+
if len(items) == 1:
|
|
303
|
+
return items[0]
|
|
304
|
+
return shlex.join(items)
|
|
305
|
+
return str(raw_command or "")
|
|
56
306
|
|
|
57
307
|
|
|
58
308
|
def _read_only_tool_annotations(*, title: str | None = None) -> ToolAnnotations:
|
|
@@ -69,6 +319,158 @@ def _metric_validation_error_payload(exc: MetricContractValidationError) -> dict
|
|
|
69
319
|
return exc.as_payload()
|
|
70
320
|
|
|
71
321
|
|
|
322
|
+
def _artifact_call(name: str, why: str) -> dict[str, str]:
|
|
323
|
+
return {"name": name, "why": why}
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
def _artifact_guided_error_payload(
|
|
327
|
+
service: ArtifactService,
|
|
328
|
+
quest_root: Path,
|
|
329
|
+
*,
|
|
330
|
+
tool_name: str,
|
|
331
|
+
exc: Exception,
|
|
332
|
+
) -> dict[str, Any]:
|
|
333
|
+
message = str(exc).strip() or f"`artifact.{tool_name}` failed."
|
|
334
|
+
guidance: list[str] = []
|
|
335
|
+
suggested_artifact_calls: list[dict[str, str]] = []
|
|
336
|
+
extra: dict[str, Any] = {}
|
|
337
|
+
|
|
338
|
+
if "selected_outline_ref" in message or "No selected outline is available" in message:
|
|
339
|
+
outlines = service.list_paper_outlines(quest_root)
|
|
340
|
+
outline_items = [dict(item) for item in (outlines.get("outlines") or []) if isinstance(item, dict)]
|
|
341
|
+
candidate_ids = [
|
|
342
|
+
str(item.get("outline_id") or "").strip()
|
|
343
|
+
for item in outline_items
|
|
344
|
+
if str(item.get("status") or "").strip() in {"candidate", "revised"}
|
|
345
|
+
and str(item.get("outline_id") or "").strip()
|
|
346
|
+
]
|
|
347
|
+
extra["outline_candidates"] = outline_items
|
|
348
|
+
if candidate_ids:
|
|
349
|
+
guidance.append(f"Select a candidate outline first. Available candidates: {', '.join(candidate_ids[:5])}.")
|
|
350
|
+
guidance.append(
|
|
351
|
+
"Use `artifact.submit_paper_outline(mode='select', outline_id='...', selected_reason='...')` "
|
|
352
|
+
"to promote one of those candidates before retrying the writing-facing campaign."
|
|
353
|
+
)
|
|
354
|
+
suggested_artifact_calls.append(
|
|
355
|
+
_artifact_call(
|
|
356
|
+
"artifact.submit_paper_outline(mode='select', outline_id='...', selected_reason='...')",
|
|
357
|
+
"Promote one candidate outline into the active paper line.",
|
|
358
|
+
)
|
|
359
|
+
)
|
|
360
|
+
else:
|
|
361
|
+
guidance.append("Create a candidate outline first, then select it before launching a writing-facing analysis campaign.")
|
|
362
|
+
suggested_artifact_calls.append(
|
|
363
|
+
_artifact_call(
|
|
364
|
+
"artifact.submit_paper_outline(mode='candidate', ...)",
|
|
365
|
+
"Create the first paper outline candidate for this quest.",
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
guidance.append(
|
|
369
|
+
"If the work is only exploratory evidence and not yet bound to the paper contract, downgrade it to a pre-outline analysis-lite / non-writing-facing campaign instead."
|
|
370
|
+
)
|
|
371
|
+
suggested_artifact_calls.append(
|
|
372
|
+
_artifact_call(
|
|
373
|
+
"artifact.create_analysis_campaign(...)",
|
|
374
|
+
"Retry only after the selected outline and paper-facing fields are explicit, or simplify the campaign so it is no longer writing-facing.",
|
|
375
|
+
)
|
|
376
|
+
)
|
|
377
|
+
elif "research_questions" in message:
|
|
378
|
+
guidance.append("Provide non-empty research_questions before launching a writing-facing analysis campaign.")
|
|
379
|
+
guidance.append("The cleanest fix is to revise the selected outline so the paper contract and campaign input agree.")
|
|
380
|
+
suggested_artifact_calls.extend(
|
|
381
|
+
[
|
|
382
|
+
_artifact_call(
|
|
383
|
+
"artifact.submit_paper_outline(mode='revise', ...)",
|
|
384
|
+
"Add research_questions to the selected outline.",
|
|
385
|
+
),
|
|
386
|
+
_artifact_call(
|
|
387
|
+
"artifact.create_analysis_campaign(..., research_questions=[...], experimental_designs=[...], todo_items=[...])",
|
|
388
|
+
"Retry the campaign with explicit writing-facing fields.",
|
|
389
|
+
),
|
|
390
|
+
]
|
|
391
|
+
)
|
|
392
|
+
elif "experimental_designs" in message:
|
|
393
|
+
guidance.append("Provide non-empty experimental_designs before launching a writing-facing analysis campaign.")
|
|
394
|
+
guidance.append("If the paper contract is still thin, revise the selected outline before retrying.")
|
|
395
|
+
suggested_artifact_calls.extend(
|
|
396
|
+
[
|
|
397
|
+
_artifact_call(
|
|
398
|
+
"artifact.submit_paper_outline(mode='revise', ...)",
|
|
399
|
+
"Add experimental_designs to the selected outline.",
|
|
400
|
+
),
|
|
401
|
+
_artifact_call(
|
|
402
|
+
"artifact.create_analysis_campaign(..., experimental_designs=[...])",
|
|
403
|
+
"Retry the campaign with explicit experimental designs.",
|
|
404
|
+
),
|
|
405
|
+
]
|
|
406
|
+
)
|
|
407
|
+
elif "todo_items" in message or "outline-bound paper contract fields" in message:
|
|
408
|
+
guidance.append("Every writing-facing analysis slice needs a todo item with section_id, item_id, paper_role, and claim_links.")
|
|
409
|
+
guidance.append("Do not launch a paper-facing campaign until every slice is mapped back into the outline contract.")
|
|
410
|
+
suggested_artifact_calls.append(
|
|
411
|
+
_artifact_call(
|
|
412
|
+
"artifact.create_analysis_campaign(..., todo_items=[...])",
|
|
413
|
+
"Retry with one outline-bound todo item per slice.",
|
|
414
|
+
)
|
|
415
|
+
)
|
|
416
|
+
elif "confirmed or waived baseline gate" in message:
|
|
417
|
+
guidance.append("Open the baseline gate first, or explicitly waive it if skipping is justified.")
|
|
418
|
+
suggested_artifact_calls.extend(
|
|
419
|
+
[
|
|
420
|
+
_artifact_call("artifact.confirm_baseline(...)", "Confirm the active baseline and metric contract."),
|
|
421
|
+
_artifact_call("artifact.waive_baseline(...)", "Record an explicit waiver if baseline work should be skipped."),
|
|
422
|
+
]
|
|
423
|
+
)
|
|
424
|
+
elif "An active idea is required before starting an analysis campaign." in message:
|
|
425
|
+
guidance.append("Create or activate an idea before launching an analysis campaign.")
|
|
426
|
+
suggested_artifact_calls.extend(
|
|
427
|
+
[
|
|
428
|
+
_artifact_call("artifact.submit_idea(...)", "Create the next durable idea route first."),
|
|
429
|
+
_artifact_call("artifact.activate_branch(...)", "Switch back to the branch that owns the accepted idea line."),
|
|
430
|
+
]
|
|
431
|
+
)
|
|
432
|
+
elif "baseline_path" in message:
|
|
433
|
+
guidance.append("Use a quest-local baseline path under `baselines/local/...` or `baselines/imported/...`.")
|
|
434
|
+
guidance.append("If the baseline lives outside the quest, materialize or attach it first instead of passing an external path directly.")
|
|
435
|
+
suggested_artifact_calls.extend(
|
|
436
|
+
[
|
|
437
|
+
_artifact_call("artifact.attach_baseline(...)", "Attach a reusable baseline package when one already exists."),
|
|
438
|
+
_artifact_call("artifact.confirm_baseline(...)", "Confirm the quest-local baseline after it is materialized."),
|
|
439
|
+
]
|
|
440
|
+
)
|
|
441
|
+
elif "imported baseline" in message or "protocol-breaking" in message:
|
|
442
|
+
guidance.append("Do not overwrite the accepted baseline in place when comparability changed materially.")
|
|
443
|
+
guidance.append("Use a new baseline id or a new variant when the path, protocol, or comparator meaning changed.")
|
|
444
|
+
suggested_artifact_calls.extend(
|
|
445
|
+
[
|
|
446
|
+
_artifact_call("artifact.confirm_baseline(...)", "Confirm the new baseline or variant as a separate comparator."),
|
|
447
|
+
_artifact_call("artifact.overwrite_baseline(...)", "Use overwrite only when the baseline is still the same accepted comparator."),
|
|
448
|
+
]
|
|
449
|
+
)
|
|
450
|
+
elif "submit_paper_bundle requires a selected outline" in message:
|
|
451
|
+
guidance.append("Select an outline before bundling the paper package.")
|
|
452
|
+
suggested_artifact_calls.append(
|
|
453
|
+
_artifact_call(
|
|
454
|
+
"artifact.submit_paper_outline(mode='select', outline_id='...', selected_reason='...')",
|
|
455
|
+
"Select the active outline before generating the final paper bundle.",
|
|
456
|
+
)
|
|
457
|
+
)
|
|
458
|
+
else:
|
|
459
|
+
guidance.append("Inspect the current quest state and the tool-specific required fields before retrying.")
|
|
460
|
+
suggested_artifact_calls.append(
|
|
461
|
+
_artifact_call("artifact.get_quest_state(detail='full')", "Read the current durable quest state before retrying the tool.")
|
|
462
|
+
)
|
|
463
|
+
|
|
464
|
+
return {
|
|
465
|
+
"ok": False,
|
|
466
|
+
"tool_name": f"artifact.{tool_name}",
|
|
467
|
+
"message": message,
|
|
468
|
+
"guidance": guidance,
|
|
469
|
+
"suggested_artifact_calls": suggested_artifact_calls,
|
|
470
|
+
**extra,
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
|
|
72
474
|
def _progress_watchdog_note(tool_call_count: int) -> str:
|
|
73
475
|
return (
|
|
74
476
|
"By the way, you have gone "
|
|
@@ -152,6 +554,180 @@ def _attach_interaction_watchdog(
|
|
|
152
554
|
return enriched
|
|
153
555
|
|
|
154
556
|
|
|
557
|
+
def _local_daemon_api_base_url(home: Path) -> tuple[str | None, dict[str, Any]]:
|
|
558
|
+
state = read_json(home / "runtime" / "daemon.json", {})
|
|
559
|
+
if not isinstance(state, dict):
|
|
560
|
+
return None, {}
|
|
561
|
+
for key in ("url", "bind_url"):
|
|
562
|
+
value = str(state.get(key) or "").strip()
|
|
563
|
+
if value:
|
|
564
|
+
return value.rstrip("/"), state
|
|
565
|
+
return None, state
|
|
566
|
+
|
|
567
|
+
|
|
568
|
+
def _issue_draft_route_effect(payload: dict[str, Any]) -> dict[str, Any]:
|
|
569
|
+
return {
|
|
570
|
+
"name": "route:navigate",
|
|
571
|
+
"data": {
|
|
572
|
+
"to": "/settings/issues",
|
|
573
|
+
"issueDraft": {
|
|
574
|
+
"ok": True,
|
|
575
|
+
"title": str(payload.get("title") or "").strip(),
|
|
576
|
+
"body_markdown": str(payload.get("body_markdown") or "").strip(),
|
|
577
|
+
"issue_url_base": str(payload.get("issue_url_base") or "").strip(),
|
|
578
|
+
"repo_url": str(payload.get("repo_url") or "").strip(),
|
|
579
|
+
"generated_at": payload.get("generated_at"),
|
|
580
|
+
},
|
|
581
|
+
},
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
|
|
585
|
+
def _coerce_prepare_bool(value: Any, *, field_name: str) -> bool:
|
|
586
|
+
if isinstance(value, bool):
|
|
587
|
+
return value
|
|
588
|
+
if isinstance(value, str):
|
|
589
|
+
normalized = value.strip().lower()
|
|
590
|
+
if normalized in {"true", "1", "yes", "on"}:
|
|
591
|
+
return True
|
|
592
|
+
if normalized in {"false", "0", "no", "off"}:
|
|
593
|
+
return False
|
|
594
|
+
raise ValueError(f"`{field_name}` must be a boolean.")
|
|
595
|
+
|
|
596
|
+
|
|
597
|
+
def _sanitize_start_setup_form_patch(form_patch: dict[str, Any] | None) -> dict[str, Any]:
|
|
598
|
+
if form_patch is None:
|
|
599
|
+
return {}
|
|
600
|
+
if not isinstance(form_patch, dict):
|
|
601
|
+
raise ValueError("`form_patch` must be an object.")
|
|
602
|
+
patch: dict[str, Any] = {}
|
|
603
|
+
for key in START_SETUP_FORM_FIELDS:
|
|
604
|
+
if key not in form_patch:
|
|
605
|
+
continue
|
|
606
|
+
value = form_patch.get(key)
|
|
607
|
+
if value is None:
|
|
608
|
+
continue
|
|
609
|
+
if key == "need_research_paper":
|
|
610
|
+
patch[key] = _coerce_prepare_bool(value, field_name=key)
|
|
611
|
+
continue
|
|
612
|
+
if isinstance(value, (str, int, float, bool)):
|
|
613
|
+
patch[key] = str(value).strip() if not isinstance(value, bool) else value
|
|
614
|
+
continue
|
|
615
|
+
raise ValueError(f"`form_patch.{key}` must be a string or boolean.")
|
|
616
|
+
return patch
|
|
617
|
+
|
|
618
|
+
|
|
619
|
+
def _sanitize_start_setup_session_patch(session_patch: dict[str, Any] | None) -> dict[str, Any]:
|
|
620
|
+
if session_patch is None:
|
|
621
|
+
return {}
|
|
622
|
+
if not isinstance(session_patch, dict):
|
|
623
|
+
raise ValueError("`session_patch` must be an object.")
|
|
624
|
+
patch: dict[str, Any] = {}
|
|
625
|
+
for key in START_SETUP_SESSION_FIELDS:
|
|
626
|
+
if key not in session_patch:
|
|
627
|
+
continue
|
|
628
|
+
value = session_patch.get(key)
|
|
629
|
+
if value is None:
|
|
630
|
+
continue
|
|
631
|
+
if key in {"recommended_workspace_mode", "launch_readiness"}:
|
|
632
|
+
patch[key] = str(value).strip()
|
|
633
|
+
continue
|
|
634
|
+
if key == "missing_confirmations":
|
|
635
|
+
if not isinstance(value, list):
|
|
636
|
+
raise ValueError("`session_patch.missing_confirmations` must be an array of strings.")
|
|
637
|
+
patch[key] = [str(item).strip() for item in value if str(item).strip()]
|
|
638
|
+
continue
|
|
639
|
+
if key == "science_package_cards":
|
|
640
|
+
if not isinstance(value, list):
|
|
641
|
+
raise ValueError("`session_patch.science_package_cards` must be an array of strings.")
|
|
642
|
+
patch[key] = [str(item).strip() for item in value if str(item).strip()]
|
|
643
|
+
continue
|
|
644
|
+
if key in {"fit_assessment", "preview_plan", "copilot_handoff", "science_task", "science_task_brief"}:
|
|
645
|
+
if not isinstance(value, dict):
|
|
646
|
+
raise ValueError(f"`session_patch.{key}` must be an object.")
|
|
647
|
+
patch[key] = json.loads(json.dumps(value, ensure_ascii=False))
|
|
648
|
+
continue
|
|
649
|
+
if key == "materials_summary":
|
|
650
|
+
if not isinstance(value, list):
|
|
651
|
+
raise ValueError("`session_patch.materials_summary` must be an array.")
|
|
652
|
+
patch[key] = [dict(item) for item in value if isinstance(item, dict)]
|
|
653
|
+
continue
|
|
654
|
+
return patch
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
def _start_setup_patch_effect(
|
|
658
|
+
form_patch: dict[str, Any],
|
|
659
|
+
*,
|
|
660
|
+
session_patch: dict[str, Any] | None = None,
|
|
661
|
+
message: str | None = None,
|
|
662
|
+
) -> dict[str, Any]:
|
|
663
|
+
return {
|
|
664
|
+
"name": "start_setup:patch",
|
|
665
|
+
"data": {
|
|
666
|
+
"patch": dict(form_patch),
|
|
667
|
+
"session_patch": dict(session_patch or {}),
|
|
668
|
+
"message": str(message or "").strip() or None,
|
|
669
|
+
},
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
def _prepare_github_issue_payload_via_daemon(
|
|
674
|
+
home: Path,
|
|
675
|
+
*,
|
|
676
|
+
summary: str | None = None,
|
|
677
|
+
user_notes: str | None = None,
|
|
678
|
+
include_doctor: bool = True,
|
|
679
|
+
include_logs: bool = True,
|
|
680
|
+
include_system_quirks: bool = False,
|
|
681
|
+
) -> dict[str, Any]:
|
|
682
|
+
base_url, daemon_state = _local_daemon_api_base_url(home)
|
|
683
|
+
if not base_url:
|
|
684
|
+
raise ValueError("The local daemon URL is unavailable. Start DeepScientist before preparing a GitHub issue draft.")
|
|
685
|
+
|
|
686
|
+
token = str((daemon_state or {}).get("auth_token") or "").strip()
|
|
687
|
+
auth_enabled = bool((daemon_state or {}).get("auth_enabled"))
|
|
688
|
+
if auth_enabled and not token:
|
|
689
|
+
raise ValueError("Browser auth is enabled for the local daemon, but no auth token was found in runtime/daemon.json.")
|
|
690
|
+
|
|
691
|
+
body = {
|
|
692
|
+
"summary": str(summary or "").strip() or None,
|
|
693
|
+
"user_notes": str(user_notes or "").strip() or None,
|
|
694
|
+
"include_doctor": bool(include_doctor),
|
|
695
|
+
"include_logs": bool(include_logs),
|
|
696
|
+
"include_system_quirks": bool(include_system_quirks),
|
|
697
|
+
}
|
|
698
|
+
headers = {
|
|
699
|
+
"Content-Type": "application/json",
|
|
700
|
+
}
|
|
701
|
+
if auth_enabled and token:
|
|
702
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
703
|
+
|
|
704
|
+
request = urllib_request.Request(
|
|
705
|
+
f"{base_url}/api/system/issues/draft",
|
|
706
|
+
data=json.dumps(body).encode("utf-8"),
|
|
707
|
+
headers=headers,
|
|
708
|
+
method="POST",
|
|
709
|
+
)
|
|
710
|
+
try:
|
|
711
|
+
with urllib_request.urlopen(request, timeout=15) as response:
|
|
712
|
+
raw = response.read().decode("utf-8", errors="replace")
|
|
713
|
+
except urllib_error.HTTPError as exc: # pragma: no cover - exercised via unit monkeypatching
|
|
714
|
+
detail = exc.read().decode("utf-8", errors="replace").strip()
|
|
715
|
+
message = detail or getattr(exc, "reason", "") or "request failed"
|
|
716
|
+
raise ValueError(f"Local daemon issue draft request failed with HTTP {exc.code}: {message}") from exc
|
|
717
|
+
except OSError as exc:
|
|
718
|
+
raise ValueError(f"Unable to reach the local daemon at `{base_url}`: {exc}") from exc
|
|
719
|
+
|
|
720
|
+
try:
|
|
721
|
+
payload = json.loads(raw or "{}")
|
|
722
|
+
except json.JSONDecodeError as exc:
|
|
723
|
+
raise ValueError("The local daemon returned an invalid issue draft payload.") from exc
|
|
724
|
+
if not isinstance(payload, dict):
|
|
725
|
+
raise ValueError("The local daemon returned a non-object issue draft payload.")
|
|
726
|
+
if payload.get("ok") is False:
|
|
727
|
+
raise ValueError(str(payload.get("message") or "The local daemon rejected the issue draft request."))
|
|
728
|
+
return payload
|
|
729
|
+
|
|
730
|
+
|
|
155
731
|
def _split_bash_log_lines(log_text: str) -> list[str]:
|
|
156
732
|
return log_text.splitlines()
|
|
157
733
|
|
|
@@ -421,8 +997,31 @@ def build_memory_server(context: McpContext) -> FastMCP:
|
|
|
421
997
|
comment: str | dict[str, Any] | None = None,
|
|
422
998
|
) -> dict[str, Any]:
|
|
423
999
|
resolved_scope = _resolve_search_scope(context, scope)
|
|
424
|
-
|
|
425
|
-
|
|
1000
|
+
if resolved_scope == "quest" and context.quest_root is not None and service.shared_read_enabled():
|
|
1001
|
+
items = service.search_visible_quest_cards(
|
|
1002
|
+
query,
|
|
1003
|
+
active_quest_root=context.quest_root,
|
|
1004
|
+
active_quest_id=context.quest_id,
|
|
1005
|
+
limit=limit,
|
|
1006
|
+
kind=kind,
|
|
1007
|
+
include_shared=True,
|
|
1008
|
+
)
|
|
1009
|
+
elif resolved_scope == "both" and context.quest_root is not None:
|
|
1010
|
+
quest_items = service.search_visible_quest_cards(
|
|
1011
|
+
query,
|
|
1012
|
+
active_quest_root=context.quest_root,
|
|
1013
|
+
active_quest_id=context.quest_id,
|
|
1014
|
+
limit=limit,
|
|
1015
|
+
kind=kind,
|
|
1016
|
+
include_shared=service.shared_read_enabled(),
|
|
1017
|
+
)
|
|
1018
|
+
global_items = service.search(query, scope="global", limit=limit, kind=kind)
|
|
1019
|
+
items = quest_items + global_items
|
|
1020
|
+
items.sort(key=lambda item: service._visible_card_sort_key(item, active_quest_id=context.quest_id))
|
|
1021
|
+
items = items[:limit]
|
|
1022
|
+
else:
|
|
1023
|
+
quest_root = context.quest_root if resolved_scope in {"quest", "both"} else None
|
|
1024
|
+
items = service.search(query, scope=resolved_scope, quest_root=quest_root, limit=limit, kind=kind)
|
|
426
1025
|
return {"ok": True, "count": len(items), "items": items}
|
|
427
1026
|
|
|
428
1027
|
@server.tool(
|
|
@@ -440,10 +1039,30 @@ def build_memory_server(context: McpContext) -> FastMCP:
|
|
|
440
1039
|
comment: str | dict[str, Any] | None = None,
|
|
441
1040
|
) -> dict[str, Any]:
|
|
442
1041
|
resolved_scope = _resolve_search_scope(context, scope)
|
|
443
|
-
if resolved_scope == "
|
|
444
|
-
|
|
1042
|
+
if resolved_scope == "quest" and context.quest_root is not None and service.shared_read_enabled():
|
|
1043
|
+
items = service.list_visible_quest_cards(
|
|
1044
|
+
active_quest_root=context.quest_root,
|
|
1045
|
+
active_quest_id=context.quest_id,
|
|
1046
|
+
limit=limit,
|
|
1047
|
+
kind=kind,
|
|
1048
|
+
include_shared=True,
|
|
1049
|
+
)
|
|
1050
|
+
elif resolved_scope == "both":
|
|
1051
|
+
quest_items = (
|
|
1052
|
+
service.list_visible_quest_cards(
|
|
1053
|
+
active_quest_root=context.require_quest_root(),
|
|
1054
|
+
active_quest_id=context.quest_id,
|
|
1055
|
+
limit=limit,
|
|
1056
|
+
kind=kind,
|
|
1057
|
+
include_shared=service.shared_read_enabled(),
|
|
1058
|
+
)
|
|
1059
|
+
if context.quest_root is not None
|
|
1060
|
+
else []
|
|
1061
|
+
)
|
|
445
1062
|
global_items = service.list_recent(scope="global", limit=limit, kind=kind)
|
|
446
|
-
items =
|
|
1063
|
+
items = quest_items + global_items
|
|
1064
|
+
items.sort(key=lambda item: service._visible_card_sort_key(item, active_quest_id=context.quest_id))
|
|
1065
|
+
items = items[:limit]
|
|
447
1066
|
else:
|
|
448
1067
|
quest_root = context.quest_root if resolved_scope == "quest" else None
|
|
449
1068
|
items = service.list_recent(scope=resolved_scope, quest_root=quest_root, limit=limit, kind=kind)
|
|
@@ -469,6 +1088,9 @@ def build_memory_server(context: McpContext) -> FastMCP:
|
|
|
469
1088
|
def build_artifact_server(context: McpContext) -> FastMCP:
|
|
470
1089
|
service = ArtifactService(context.home)
|
|
471
1090
|
quest_service = service.quest_service
|
|
1091
|
+
custom_profile = str(context.custom_profile or "").strip().lower()
|
|
1092
|
+
issue_only_profile = custom_profile == "settings_issue"
|
|
1093
|
+
start_setup_prepare_profile = custom_profile == "start_setup_prepare"
|
|
472
1094
|
server = FastMCP(
|
|
473
1095
|
"artifact",
|
|
474
1096
|
instructions=(
|
|
@@ -479,7 +1101,12 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
479
1101
|
log_level="ERROR",
|
|
480
1102
|
)
|
|
481
1103
|
|
|
482
|
-
def
|
|
1104
|
+
def finalize_artifact_tool(
|
|
1105
|
+
payload: dict[str, Any],
|
|
1106
|
+
*,
|
|
1107
|
+
tool_name: str,
|
|
1108
|
+
state_change_note: str | None = None,
|
|
1109
|
+
) -> dict[str, Any]:
|
|
483
1110
|
quest_root = context.require_quest_root().resolve()
|
|
484
1111
|
quest_service.record_tool_activity(
|
|
485
1112
|
quest_root,
|
|
@@ -489,9 +1116,188 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
489
1116
|
return _attach_interaction_watchdog(
|
|
490
1117
|
payload,
|
|
491
1118
|
watchdog,
|
|
1119
|
+
state_change_note=state_change_note,
|
|
1120
|
+
)
|
|
1121
|
+
|
|
1122
|
+
def finalize_state_changing_artifact_tool(payload: dict[str, Any], *, tool_name: str) -> dict[str, Any]:
|
|
1123
|
+
return finalize_artifact_tool(
|
|
1124
|
+
payload,
|
|
1125
|
+
tool_name=tool_name,
|
|
492
1126
|
state_change_note=ARTIFACT_STATE_CHANGE_WATCHDOG_NOTES.get(tool_name),
|
|
493
1127
|
)
|
|
494
1128
|
|
|
1129
|
+
def _quest_relative_path(value: Any) -> str | None:
|
|
1130
|
+
text = str(value or "").strip()
|
|
1131
|
+
if not text:
|
|
1132
|
+
return None
|
|
1133
|
+
path = Path(text)
|
|
1134
|
+
if not path.is_absolute():
|
|
1135
|
+
return text
|
|
1136
|
+
quest_root = context.require_quest_root().resolve()
|
|
1137
|
+
try:
|
|
1138
|
+
active_workspace_root = quest_service.active_workspace_root(quest_root)
|
|
1139
|
+
except Exception:
|
|
1140
|
+
active_workspace_root = None
|
|
1141
|
+
roots = [context.worktree_root, active_workspace_root, context.quest_root]
|
|
1142
|
+
seen: set[str] = set()
|
|
1143
|
+
for raw_root in roots:
|
|
1144
|
+
if raw_root is None:
|
|
1145
|
+
continue
|
|
1146
|
+
root = raw_root.resolve()
|
|
1147
|
+
key = str(root)
|
|
1148
|
+
if key in seen:
|
|
1149
|
+
continue
|
|
1150
|
+
seen.add(key)
|
|
1151
|
+
try:
|
|
1152
|
+
return path.resolve().relative_to(root).as_posix()
|
|
1153
|
+
except ValueError:
|
|
1154
|
+
continue
|
|
1155
|
+
try:
|
|
1156
|
+
return path.resolve().relative_to(quest_root).as_posix()
|
|
1157
|
+
except ValueError:
|
|
1158
|
+
return text
|
|
1159
|
+
|
|
1160
|
+
def _compact_artifact_delta(value: Any) -> dict[str, Any] | None:
|
|
1161
|
+
if not isinstance(value, dict):
|
|
1162
|
+
return None
|
|
1163
|
+
return {
|
|
1164
|
+
key: value.get(key)
|
|
1165
|
+
for key in (
|
|
1166
|
+
"schema_version",
|
|
1167
|
+
"delta_id",
|
|
1168
|
+
"delta_kind",
|
|
1169
|
+
"sidecar_rel_path",
|
|
1170
|
+
"path_count",
|
|
1171
|
+
"changed_paths",
|
|
1172
|
+
)
|
|
1173
|
+
if value.get(key) is not None
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
def _compact_paths(payload: dict[str, Any], keys: tuple[str, ...]) -> dict[str, str]:
|
|
1177
|
+
paths: dict[str, str] = {}
|
|
1178
|
+
for key in keys:
|
|
1179
|
+
relative = _quest_relative_path(payload.get(key))
|
|
1180
|
+
if relative:
|
|
1181
|
+
paths[key] = relative
|
|
1182
|
+
return paths
|
|
1183
|
+
|
|
1184
|
+
def compact_paper_write_result(payload: dict[str, Any], *, tool_name: str) -> dict[str, Any]:
|
|
1185
|
+
compact: dict[str, Any] = {
|
|
1186
|
+
"ok": bool(payload.get("ok")),
|
|
1187
|
+
"tool_name": tool_name,
|
|
1188
|
+
"artifact_delta": _compact_artifact_delta(payload.get("artifact_delta")),
|
|
1189
|
+
"hint": "Full paper artifact content was written to files; read the listed paths or artifact_delta sidecar only when needed.",
|
|
1190
|
+
}
|
|
1191
|
+
if tool_name == "submit_paper_outline":
|
|
1192
|
+
compact.update(
|
|
1193
|
+
{
|
|
1194
|
+
"mode": payload.get("mode"),
|
|
1195
|
+
"outline_id": payload.get("outline_id"),
|
|
1196
|
+
"paths": _compact_paths(
|
|
1197
|
+
payload,
|
|
1198
|
+
(
|
|
1199
|
+
"outline_path",
|
|
1200
|
+
"selected_outline_path",
|
|
1201
|
+
"outline_manifest_path",
|
|
1202
|
+
"paper_line_state_path",
|
|
1203
|
+
"outline_selection_path",
|
|
1204
|
+
"revised_outline_path",
|
|
1205
|
+
),
|
|
1206
|
+
),
|
|
1207
|
+
}
|
|
1208
|
+
)
|
|
1209
|
+
return compact
|
|
1210
|
+
|
|
1211
|
+
manifest = payload.get("manifest") if isinstance(payload.get("manifest"), dict) else {}
|
|
1212
|
+
paper_line_state = payload.get("paper_line_state") if isinstance(payload.get("paper_line_state"), dict) else {}
|
|
1213
|
+
continuation = payload.get("continuation") if isinstance(payload.get("continuation"), dict) else {}
|
|
1214
|
+
compact.update(
|
|
1215
|
+
{
|
|
1216
|
+
"package_type": manifest.get("package_type"),
|
|
1217
|
+
"title": manifest.get("title"),
|
|
1218
|
+
"selected_outline_ref": manifest.get("selected_outline_ref"),
|
|
1219
|
+
"paper_branch": manifest.get("paper_branch") or paper_line_state.get("paper_branch"),
|
|
1220
|
+
"next_anchor": continuation.get("anchor") or "decision",
|
|
1221
|
+
"paths": _compact_paths(
|
|
1222
|
+
payload,
|
|
1223
|
+
(
|
|
1224
|
+
"manifest_path",
|
|
1225
|
+
"baseline_inventory_path",
|
|
1226
|
+
"evidence_ledger_path",
|
|
1227
|
+
"paper_line_state_path",
|
|
1228
|
+
"manuscript_coverage_path",
|
|
1229
|
+
"open_source_manifest_path",
|
|
1230
|
+
),
|
|
1231
|
+
),
|
|
1232
|
+
}
|
|
1233
|
+
)
|
|
1234
|
+
return compact
|
|
1235
|
+
|
|
1236
|
+
if issue_only_profile:
|
|
1237
|
+
@server.tool(
|
|
1238
|
+
name="prepare_github_issue",
|
|
1239
|
+
description=(
|
|
1240
|
+
"Generate a prefilled GitHub issue draft from the live local daemon's settings diagnostics. "
|
|
1241
|
+
"By default this also asks the browser UI to navigate to `/settings/issues` and preload the generated draft."
|
|
1242
|
+
),
|
|
1243
|
+
)
|
|
1244
|
+
def prepare_github_issue(
|
|
1245
|
+
summary: str = "",
|
|
1246
|
+
user_notes: str = "",
|
|
1247
|
+
include_doctor: bool = True,
|
|
1248
|
+
include_logs: bool = True,
|
|
1249
|
+
include_system_quirks: bool = False,
|
|
1250
|
+
open_settings_page: bool = True,
|
|
1251
|
+
comment: str | dict[str, Any] | None = None,
|
|
1252
|
+
) -> dict[str, Any]:
|
|
1253
|
+
result = _prepare_github_issue_payload_via_daemon(
|
|
1254
|
+
context.home,
|
|
1255
|
+
summary=summary,
|
|
1256
|
+
user_notes=user_notes,
|
|
1257
|
+
include_doctor=include_doctor,
|
|
1258
|
+
include_logs=include_logs,
|
|
1259
|
+
include_system_quirks=include_system_quirks,
|
|
1260
|
+
)
|
|
1261
|
+
if open_settings_page:
|
|
1262
|
+
result["ui_effects"] = [_issue_draft_route_effect(result)]
|
|
1263
|
+
return finalize_artifact_tool(result, tool_name="prepare_github_issue")
|
|
1264
|
+
|
|
1265
|
+
return server
|
|
1266
|
+
|
|
1267
|
+
if start_setup_prepare_profile:
|
|
1268
|
+
@server.tool(
|
|
1269
|
+
name="prepare_start_setup_form",
|
|
1270
|
+
description=(
|
|
1271
|
+
"Prepare and apply a structured patch for the autonomous start form. "
|
|
1272
|
+
"Use this when the setup agent has enough information to fill or refine the form automatically."
|
|
1273
|
+
),
|
|
1274
|
+
)
|
|
1275
|
+
def prepare_start_setup_form(
|
|
1276
|
+
form_patch: dict[str, Any] | None = None,
|
|
1277
|
+
session_patch: dict[str, Any] | None = None,
|
|
1278
|
+
message: str = "",
|
|
1279
|
+
comment: str | dict[str, Any] | None = None,
|
|
1280
|
+
) -> dict[str, Any]:
|
|
1281
|
+
nested_form_patch, nested_session_patch = _split_nested_start_setup_payload(form_patch)
|
|
1282
|
+
if nested_form_patch is not None:
|
|
1283
|
+
form_patch = nested_form_patch
|
|
1284
|
+
if session_patch is None and nested_session_patch is not None:
|
|
1285
|
+
session_patch = nested_session_patch
|
|
1286
|
+
sanitized_patch = _sanitize_start_setup_form_patch(form_patch)
|
|
1287
|
+
sanitized_session_patch = _sanitize_start_setup_session_patch(session_patch)
|
|
1288
|
+
if not sanitized_patch and not sanitized_session_patch:
|
|
1289
|
+
raise ValueError("At least one of `form_patch` or `session_patch` must include supported fields.")
|
|
1290
|
+
result = service.apply_start_setup_form_patch(
|
|
1291
|
+
context.require_quest_root(),
|
|
1292
|
+
form_patch=sanitized_patch,
|
|
1293
|
+
session_patch=sanitized_session_patch,
|
|
1294
|
+
message=message,
|
|
1295
|
+
)
|
|
1296
|
+
result["ui_effects"] = [_start_setup_patch_effect(sanitized_patch, session_patch=sanitized_session_patch, message=message)]
|
|
1297
|
+
return finalize_artifact_tool(result, tool_name="prepare_start_setup_form")
|
|
1298
|
+
|
|
1299
|
+
return server
|
|
1300
|
+
|
|
495
1301
|
@server.tool(name="record", description="Write a structured artifact record under the current quest.")
|
|
496
1302
|
def record(payload: dict[str, Any], comment: str | dict[str, Any] | None = None) -> dict[str, Any]:
|
|
497
1303
|
enriched = dict(payload)
|
|
@@ -514,6 +1320,94 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
514
1320
|
workspace_root=context.worktree_root,
|
|
515
1321
|
)
|
|
516
1322
|
|
|
1323
|
+
@server.tool(
|
|
1324
|
+
name="science",
|
|
1325
|
+
description=(
|
|
1326
|
+
"Record and update Science Evidence Graph nodes under the artifact namespace. "
|
|
1327
|
+
"Use this for natural-science and engineering package checks, computational runs, dataset analyses, "
|
|
1328
|
+
"parameter sweeps, validation results, and scientific claims. Do not use it for execution; "
|
|
1329
|
+
"all commands, solver runs, SSH, and HPC work must go through bash_exec."
|
|
1330
|
+
),
|
|
1331
|
+
)
|
|
1332
|
+
def science(
|
|
1333
|
+
action: str,
|
|
1334
|
+
node_type: str | None = None,
|
|
1335
|
+
node_id: str | None = None,
|
|
1336
|
+
title: str | None = None,
|
|
1337
|
+
summary: str | None = None,
|
|
1338
|
+
status: str | None = None,
|
|
1339
|
+
domain: str | None = None,
|
|
1340
|
+
package_id: str | None = None,
|
|
1341
|
+
task_type: str | None = None,
|
|
1342
|
+
key_results: list[dict[str, Any]] | None = None,
|
|
1343
|
+
evidence_paths: list[str] | None = None,
|
|
1344
|
+
input_paths: list[str] | None = None,
|
|
1345
|
+
output_paths: list[str] | None = None,
|
|
1346
|
+
log_paths: list[str] | None = None,
|
|
1347
|
+
validation_paths: list[str] | None = None,
|
|
1348
|
+
parent_node_ids: list[str] | None = None,
|
|
1349
|
+
related_node_ids: list[str] | None = None,
|
|
1350
|
+
claim_type: str | None = None,
|
|
1351
|
+
trust: str | None = None,
|
|
1352
|
+
canvas: dict[str, Any] | None = None,
|
|
1353
|
+
notify: bool = False,
|
|
1354
|
+
relation_type: str | None = None,
|
|
1355
|
+
relation_summary: str | None = None,
|
|
1356
|
+
metadata: dict[str, Any] | None = None,
|
|
1357
|
+
comment: str | dict[str, Any] | None = None,
|
|
1358
|
+
) -> dict[str, Any]:
|
|
1359
|
+
def _normalize_paths(values: list[str] | None) -> list[str]:
|
|
1360
|
+
if not isinstance(values, list):
|
|
1361
|
+
return []
|
|
1362
|
+
normalized: list[str] = []
|
|
1363
|
+
seen: set[str] = set()
|
|
1364
|
+
for value in values:
|
|
1365
|
+
path = _quest_relative_path(value)
|
|
1366
|
+
if not path or path in seen:
|
|
1367
|
+
continue
|
|
1368
|
+
seen.add(path)
|
|
1369
|
+
normalized.append(path)
|
|
1370
|
+
return normalized
|
|
1371
|
+
|
|
1372
|
+
source: dict[str, Any] = {"kind": "agent"}
|
|
1373
|
+
if context.agent_role:
|
|
1374
|
+
source["role"] = context.agent_role
|
|
1375
|
+
if context.run_id:
|
|
1376
|
+
source["run_id"] = context.run_id
|
|
1377
|
+
if context.worker_id:
|
|
1378
|
+
source["worker_id"] = context.worker_id
|
|
1379
|
+
result = service.science(
|
|
1380
|
+
context.require_quest_root(),
|
|
1381
|
+
action=action,
|
|
1382
|
+
node_type=node_type,
|
|
1383
|
+
node_id=node_id,
|
|
1384
|
+
title=title,
|
|
1385
|
+
summary=summary,
|
|
1386
|
+
status=status,
|
|
1387
|
+
domain=domain,
|
|
1388
|
+
package_id=package_id,
|
|
1389
|
+
task_type=task_type,
|
|
1390
|
+
key_results=key_results,
|
|
1391
|
+
evidence_paths=_normalize_paths(evidence_paths),
|
|
1392
|
+
input_paths=_normalize_paths(input_paths),
|
|
1393
|
+
output_paths=_normalize_paths(output_paths),
|
|
1394
|
+
log_paths=_normalize_paths(log_paths),
|
|
1395
|
+
validation_paths=_normalize_paths(validation_paths),
|
|
1396
|
+
parent_node_ids=parent_node_ids,
|
|
1397
|
+
related_node_ids=related_node_ids,
|
|
1398
|
+
claim_type=claim_type,
|
|
1399
|
+
trust=trust,
|
|
1400
|
+
canvas=canvas,
|
|
1401
|
+
notify=notify,
|
|
1402
|
+
relation_type=relation_type,
|
|
1403
|
+
relation_summary=relation_summary,
|
|
1404
|
+
metadata=metadata,
|
|
1405
|
+
source=source,
|
|
1406
|
+
run_id=context.run_id,
|
|
1407
|
+
workspace_root=context.worktree_root,
|
|
1408
|
+
)
|
|
1409
|
+
return finalize_artifact_tool(result, tool_name="science")
|
|
1410
|
+
|
|
517
1411
|
@server.tool(name="checkpoint", description="Create a Git checkpoint in the current quest repository.")
|
|
518
1412
|
def checkpoint(
|
|
519
1413
|
message: str,
|
|
@@ -601,15 +1495,26 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
601
1495
|
create_worktree_if_missing: bool = True,
|
|
602
1496
|
comment: str | dict[str, Any] | None = None,
|
|
603
1497
|
) -> dict[str, Any]:
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
1498
|
+
try:
|
|
1499
|
+
return service.activate_branch(
|
|
1500
|
+
context.require_quest_root(),
|
|
1501
|
+
branch=branch,
|
|
1502
|
+
idea_id=idea_id,
|
|
1503
|
+
run_id=run_id,
|
|
1504
|
+
anchor=anchor,
|
|
1505
|
+
promote_to_head=promote_to_head,
|
|
1506
|
+
create_worktree_if_missing=create_worktree_if_missing,
|
|
1507
|
+
)
|
|
1508
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
1509
|
+
return finalize_artifact_tool(
|
|
1510
|
+
_artifact_guided_error_payload(
|
|
1511
|
+
service,
|
|
1512
|
+
context.require_quest_root(),
|
|
1513
|
+
tool_name="activate_branch",
|
|
1514
|
+
exc=exc,
|
|
1515
|
+
),
|
|
1516
|
+
tool_name="activate_branch",
|
|
1517
|
+
)
|
|
613
1518
|
|
|
614
1519
|
@server.tool(
|
|
615
1520
|
name="submit_idea",
|
|
@@ -646,31 +1551,42 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
646
1551
|
source_candidate_id: str | None = None,
|
|
647
1552
|
comment: str | dict[str, Any] | None = None,
|
|
648
1553
|
) -> dict[str, Any]:
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
1554
|
+
try:
|
|
1555
|
+
return service.submit_idea(
|
|
1556
|
+
context.require_quest_root(),
|
|
1557
|
+
mode=mode,
|
|
1558
|
+
submission_mode=submission_mode,
|
|
1559
|
+
idea_id=idea_id,
|
|
1560
|
+
lineage_intent=lineage_intent,
|
|
1561
|
+
title=title,
|
|
1562
|
+
problem=problem,
|
|
1563
|
+
hypothesis=hypothesis,
|
|
1564
|
+
mechanism=mechanism,
|
|
1565
|
+
method_brief=method_brief,
|
|
1566
|
+
selection_scores=selection_scores,
|
|
1567
|
+
mechanism_family=mechanism_family,
|
|
1568
|
+
change_layer=change_layer,
|
|
1569
|
+
source_lens=source_lens,
|
|
1570
|
+
expected_gain=expected_gain,
|
|
1571
|
+
evidence_paths=evidence_paths,
|
|
1572
|
+
risks=risks,
|
|
1573
|
+
decision_reason=decision_reason,
|
|
1574
|
+
foundation_ref=foundation_ref,
|
|
1575
|
+
foundation_reason=foundation_reason,
|
|
1576
|
+
next_target=next_target,
|
|
1577
|
+
draft_markdown=draft_markdown,
|
|
1578
|
+
source_candidate_id=source_candidate_id,
|
|
1579
|
+
)
|
|
1580
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
1581
|
+
return finalize_artifact_tool(
|
|
1582
|
+
_artifact_guided_error_payload(
|
|
1583
|
+
service,
|
|
1584
|
+
context.require_quest_root(),
|
|
1585
|
+
tool_name="submit_idea",
|
|
1586
|
+
exc=exc,
|
|
1587
|
+
),
|
|
1588
|
+
tool_name="submit_idea",
|
|
1589
|
+
)
|
|
674
1590
|
|
|
675
1591
|
@server.tool(
|
|
676
1592
|
name="list_research_branches",
|
|
@@ -694,6 +1610,23 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
694
1610
|
def resolve_runtime_refs(comment: str | dict[str, Any] | None = None) -> dict[str, Any]:
|
|
695
1611
|
return service.resolve_runtime_refs(context.require_quest_root())
|
|
696
1612
|
|
|
1613
|
+
@server.tool(
|
|
1614
|
+
name="get_paper_contract",
|
|
1615
|
+
description=(
|
|
1616
|
+
"Read the active paper contract, including selected outline, section result tables, evidence ledger items, "
|
|
1617
|
+
"analysis inventory, and experiment matrix rows. Use detail='full' by default when writing or finalizing from paper evidence."
|
|
1618
|
+
),
|
|
1619
|
+
annotations=_read_only_tool_annotations(title="Get paper contract"),
|
|
1620
|
+
)
|
|
1621
|
+
def get_paper_contract(
|
|
1622
|
+
detail: str = "full",
|
|
1623
|
+
comment: str | dict[str, Any] | None = None,
|
|
1624
|
+
) -> dict[str, Any]:
|
|
1625
|
+
return service.get_paper_contract(
|
|
1626
|
+
context.require_quest_root(),
|
|
1627
|
+
detail=detail,
|
|
1628
|
+
)
|
|
1629
|
+
|
|
697
1630
|
@server.tool(
|
|
698
1631
|
name="get_paper_contract_health",
|
|
699
1632
|
description=(
|
|
@@ -706,10 +1639,107 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
706
1639
|
detail: str = "summary",
|
|
707
1640
|
comment: str | dict[str, Any] | None = None,
|
|
708
1641
|
) -> dict[str, Any]:
|
|
709
|
-
|
|
1642
|
+
result = service.get_paper_contract_health(
|
|
710
1643
|
context.require_quest_root(),
|
|
711
1644
|
detail=detail,
|
|
712
1645
|
)
|
|
1646
|
+
normalized_detail = str(detail or "summary").strip().lower() or "summary"
|
|
1647
|
+
return compact_mcp_tool_result(
|
|
1648
|
+
result,
|
|
1649
|
+
quest_root=context.require_quest_root(),
|
|
1650
|
+
run_id=context.run_id,
|
|
1651
|
+
tool_name="artifact.get_paper_contract_health",
|
|
1652
|
+
detail=normalized_detail,
|
|
1653
|
+
force=normalized_detail == "full",
|
|
1654
|
+
reason="artifact_full_detail_context_budget",
|
|
1655
|
+
full_detail_requested=normalized_detail == "full",
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1658
|
+
@server.tool(
|
|
1659
|
+
name="validate_manuscript_coverage",
|
|
1660
|
+
description=(
|
|
1661
|
+
"Validate whether the current paper is only a draft checkpoint or a full manuscript/submission package. "
|
|
1662
|
+
"Checks section coverage, figures/tables, ready analysis groups, PDF, and submission checklist state."
|
|
1663
|
+
),
|
|
1664
|
+
annotations=_read_only_tool_annotations(title="Validate manuscript coverage"),
|
|
1665
|
+
)
|
|
1666
|
+
def validate_manuscript_coverage(
|
|
1667
|
+
detail: str = "summary",
|
|
1668
|
+
minimum_sections: int = 5,
|
|
1669
|
+
minimum_analysis_groups: int = 5,
|
|
1670
|
+
comment: str | dict[str, Any] | None = None,
|
|
1671
|
+
) -> dict[str, Any]:
|
|
1672
|
+
return service.validate_manuscript_coverage(
|
|
1673
|
+
context.require_quest_root(),
|
|
1674
|
+
detail=detail,
|
|
1675
|
+
minimum_sections=minimum_sections,
|
|
1676
|
+
minimum_analysis_groups=minimum_analysis_groups,
|
|
1677
|
+
)
|
|
1678
|
+
|
|
1679
|
+
@server.tool(
|
|
1680
|
+
name="validate_academic_outline",
|
|
1681
|
+
description=(
|
|
1682
|
+
"Validate that the selected outline is a real paper plan before drafting. "
|
|
1683
|
+
"Checks the one-sentence paper idea, story spine, evidence boundaries, core claims, method, evaluation plan, "
|
|
1684
|
+
"4-8 planned analyses or an explicit waiver, and implementation wording leakage."
|
|
1685
|
+
),
|
|
1686
|
+
annotations=_read_only_tool_annotations(title="Validate academic outline"),
|
|
1687
|
+
)
|
|
1688
|
+
def validate_academic_outline(
|
|
1689
|
+
detail: str = "summary",
|
|
1690
|
+
comment: str | dict[str, Any] | None = None,
|
|
1691
|
+
) -> dict[str, Any]:
|
|
1692
|
+
return service.validate_academic_outline(
|
|
1693
|
+
context.require_quest_root(),
|
|
1694
|
+
detail=detail,
|
|
1695
|
+
)
|
|
1696
|
+
|
|
1697
|
+
@server.tool(
|
|
1698
|
+
name="validate_manuscript_language",
|
|
1699
|
+
description=(
|
|
1700
|
+
"Scan paper draft/LaTeX for main-text implementation or route terms that should stay in artifact records "
|
|
1701
|
+
"or appendix reproducibility details."
|
|
1702
|
+
),
|
|
1703
|
+
annotations=_read_only_tool_annotations(title="Validate manuscript language"),
|
|
1704
|
+
)
|
|
1705
|
+
def validate_manuscript_language(
|
|
1706
|
+
detail: str = "summary",
|
|
1707
|
+
scope: str = "main_text",
|
|
1708
|
+
comment: str | dict[str, Any] | None = None,
|
|
1709
|
+
) -> dict[str, Any]:
|
|
1710
|
+
return service.validate_manuscript_language(
|
|
1711
|
+
context.require_quest_root(),
|
|
1712
|
+
detail=detail,
|
|
1713
|
+
scope=scope,
|
|
1714
|
+
)
|
|
1715
|
+
|
|
1716
|
+
@server.tool(
|
|
1717
|
+
name="compile_outline_to_writing_plan",
|
|
1718
|
+
description=(
|
|
1719
|
+
"Turn the selected outline into concrete writing jobs for introduction, method, setup, results, analyses, "
|
|
1720
|
+
"limitations, and abstract. Use after validate_academic_outline and before drafting."
|
|
1721
|
+
),
|
|
1722
|
+
)
|
|
1723
|
+
def compile_outline_to_writing_plan(
|
|
1724
|
+
detail: str = "summary",
|
|
1725
|
+
comment: str | dict[str, Any] | None = None,
|
|
1726
|
+
) -> dict[str, Any]:
|
|
1727
|
+
try:
|
|
1728
|
+
result = service.compile_outline_to_writing_plan(
|
|
1729
|
+
context.require_quest_root(),
|
|
1730
|
+
detail=detail,
|
|
1731
|
+
)
|
|
1732
|
+
return finalize_state_changing_artifact_tool(result, tool_name="compile_outline_to_writing_plan")
|
|
1733
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
1734
|
+
return finalize_artifact_tool(
|
|
1735
|
+
_artifact_guided_error_payload(
|
|
1736
|
+
service,
|
|
1737
|
+
context.require_quest_root(),
|
|
1738
|
+
tool_name="compile_outline_to_writing_plan",
|
|
1739
|
+
exc=exc,
|
|
1740
|
+
),
|
|
1741
|
+
tool_name="compile_outline_to_writing_plan",
|
|
1742
|
+
)
|
|
713
1743
|
|
|
714
1744
|
@server.tool(
|
|
715
1745
|
name="get_quest_state",
|
|
@@ -723,10 +1753,22 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
723
1753
|
detail: str = "summary",
|
|
724
1754
|
comment: str | dict[str, Any] | None = None,
|
|
725
1755
|
) -> dict[str, Any]:
|
|
726
|
-
|
|
1756
|
+
result = service.get_quest_state(
|
|
727
1757
|
context.require_quest_root(),
|
|
728
1758
|
detail=detail,
|
|
729
1759
|
)
|
|
1760
|
+
normalized_detail = str(detail or "summary").strip().lower() or "summary"
|
|
1761
|
+
return cached_compact_mcp_tool_result(
|
|
1762
|
+
result,
|
|
1763
|
+
quest_root=context.require_quest_root(),
|
|
1764
|
+
run_id=context.run_id,
|
|
1765
|
+
tool_name="artifact.get_quest_state",
|
|
1766
|
+
detail=normalized_detail,
|
|
1767
|
+
cache_key={"detail": normalized_detail},
|
|
1768
|
+
force=normalized_detail == "full",
|
|
1769
|
+
reason="artifact_full_detail_context_budget",
|
|
1770
|
+
full_detail_requested=normalized_detail == "full",
|
|
1771
|
+
)
|
|
730
1772
|
|
|
731
1773
|
@server.tool(
|
|
732
1774
|
name="get_global_status",
|
|
@@ -741,12 +1783,71 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
741
1783
|
locale: str = "zh",
|
|
742
1784
|
comment: str | dict[str, Any] | None = None,
|
|
743
1785
|
) -> dict[str, Any]:
|
|
744
|
-
|
|
1786
|
+
result = service.get_global_status(
|
|
1787
|
+
context.require_quest_root(),
|
|
1788
|
+
detail=detail,
|
|
1789
|
+
locale=locale,
|
|
1790
|
+
)
|
|
1791
|
+
normalized_detail = str(detail or "brief").strip().lower() or "brief"
|
|
1792
|
+
normalized_locale = str(locale or "zh").strip().lower() or "zh"
|
|
1793
|
+
return cached_compact_mcp_tool_result(
|
|
1794
|
+
result,
|
|
1795
|
+
quest_root=context.require_quest_root(),
|
|
1796
|
+
run_id=context.run_id,
|
|
1797
|
+
tool_name="artifact.get_global_status",
|
|
1798
|
+
detail=normalized_detail,
|
|
1799
|
+
cache_key={"detail": normalized_detail, "locale": normalized_locale},
|
|
1800
|
+
force=normalized_detail == "full",
|
|
1801
|
+
reason="artifact_full_detail_context_budget",
|
|
1802
|
+
full_detail_requested=normalized_detail == "full",
|
|
1803
|
+
)
|
|
1804
|
+
|
|
1805
|
+
@server.tool(
|
|
1806
|
+
name="get_research_map_status",
|
|
1807
|
+
description=(
|
|
1808
|
+
"Read the current research-node progress state that corresponds to the quest canvas. "
|
|
1809
|
+
"Returns the active workspace node, research head node, node history, runtime refs, canvas freshness, recommended activation ref, and Git identifiers so agents can recover progress or switch branches without guessing."
|
|
1810
|
+
),
|
|
1811
|
+
annotations=_read_only_tool_annotations(title="Get research map status"),
|
|
1812
|
+
)
|
|
1813
|
+
def get_research_map_status(
|
|
1814
|
+
detail: str = "summary",
|
|
1815
|
+
locale: str = "zh",
|
|
1816
|
+
comment: str | dict[str, Any] | None = None,
|
|
1817
|
+
) -> dict[str, Any]:
|
|
1818
|
+
return service.get_research_map_status(
|
|
745
1819
|
context.require_quest_root(),
|
|
746
1820
|
detail=detail,
|
|
747
1821
|
locale=locale,
|
|
748
1822
|
)
|
|
749
1823
|
|
|
1824
|
+
@server.tool(
|
|
1825
|
+
name="get_benchstore_catalog",
|
|
1826
|
+
description=(
|
|
1827
|
+
"Read the BenchStore catalog with current-device recommendation hints. "
|
|
1828
|
+
"Use detail='summary' for compact recommendations or detail='full' for the full structured catalog."
|
|
1829
|
+
),
|
|
1830
|
+
annotations=_read_only_tool_annotations(title="Get BenchStore catalog"),
|
|
1831
|
+
)
|
|
1832
|
+
def get_benchstore_catalog(
|
|
1833
|
+
detail: str = "summary",
|
|
1834
|
+
comment: str | dict[str, Any] | None = None,
|
|
1835
|
+
) -> dict[str, Any]:
|
|
1836
|
+
return service.get_benchstore_catalog(
|
|
1837
|
+
context.require_quest_root(),
|
|
1838
|
+
detail=detail,
|
|
1839
|
+
)
|
|
1840
|
+
|
|
1841
|
+
@server.tool(
|
|
1842
|
+
name="get_start_setup_context",
|
|
1843
|
+
description=(
|
|
1844
|
+
"Read the current autonomous start-setup context, including the suggested form and selected benchmark context when present."
|
|
1845
|
+
),
|
|
1846
|
+
annotations=_read_only_tool_annotations(title="Get start setup context"),
|
|
1847
|
+
)
|
|
1848
|
+
def get_start_setup_context(comment: str | dict[str, Any] | None = None) -> dict[str, Any]:
|
|
1849
|
+
return service.get_start_setup_context(context.require_quest_root())
|
|
1850
|
+
|
|
750
1851
|
@server.tool(
|
|
751
1852
|
name="get_method_scoreboard",
|
|
752
1853
|
description=(
|
|
@@ -883,6 +1984,16 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
883
1984
|
)
|
|
884
1985
|
except MetricContractValidationError as exc:
|
|
885
1986
|
return _metric_validation_error_payload(exc)
|
|
1987
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
1988
|
+
return finalize_artifact_tool(
|
|
1989
|
+
_artifact_guided_error_payload(
|
|
1990
|
+
service,
|
|
1991
|
+
context.require_quest_root(),
|
|
1992
|
+
tool_name="record_main_experiment",
|
|
1993
|
+
exc=exc,
|
|
1994
|
+
),
|
|
1995
|
+
tool_name="record_main_experiment",
|
|
1996
|
+
)
|
|
886
1997
|
|
|
887
1998
|
@server.tool(
|
|
888
1999
|
name="create_analysis_campaign",
|
|
@@ -903,24 +2014,39 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
903
2014
|
todo_items: list[dict[str, Any]] | None = None,
|
|
904
2015
|
comment: str | dict[str, Any] | None = None,
|
|
905
2016
|
) -> dict[str, Any]:
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
2017
|
+
try:
|
|
2018
|
+
return service.create_analysis_campaign(
|
|
2019
|
+
context.require_quest_root(),
|
|
2020
|
+
campaign_title=campaign_title,
|
|
2021
|
+
campaign_goal=campaign_goal,
|
|
2022
|
+
parent_run_id=parent_run_id,
|
|
2023
|
+
slices=slices,
|
|
2024
|
+
campaign_origin=campaign_origin,
|
|
2025
|
+
selected_outline_ref=selected_outline_ref,
|
|
2026
|
+
research_questions=research_questions,
|
|
2027
|
+
experimental_designs=experimental_designs,
|
|
2028
|
+
todo_items=todo_items,
|
|
2029
|
+
)
|
|
2030
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2031
|
+
return finalize_artifact_tool(
|
|
2032
|
+
_artifact_guided_error_payload(
|
|
2033
|
+
service,
|
|
2034
|
+
context.require_quest_root(),
|
|
2035
|
+
tool_name="create_analysis_campaign",
|
|
2036
|
+
exc=exc,
|
|
2037
|
+
),
|
|
2038
|
+
tool_name="create_analysis_campaign",
|
|
2039
|
+
)
|
|
918
2040
|
|
|
919
2041
|
@server.tool(
|
|
920
2042
|
name="submit_paper_outline",
|
|
921
2043
|
description=(
|
|
922
2044
|
"Persist a paper outline candidate, select an approved outline, or revise the selected outline. "
|
|
923
|
-
"Use this before analysis campaigns that should support final writing claims."
|
|
2045
|
+
"Use this before analysis campaigns that should support final writing claims. "
|
|
2046
|
+
"For paper-facing work, put the paper idea and section plan in detailed_outline.paper_view, "
|
|
2047
|
+
"and keep result rows, paths, run ids, and reproducibility details in detailed_outline.evidence_view. "
|
|
2048
|
+
"Good paper_view records a one-sentence thesis, what the reader should learn, evidence boundaries, "
|
|
2049
|
+
"and a 4-8 item analysis plan when the paper is mature."
|
|
924
2050
|
),
|
|
925
2051
|
)
|
|
926
2052
|
def submit_paper_outline(
|
|
@@ -935,19 +2061,33 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
935
2061
|
selected_reason: str | None = None,
|
|
936
2062
|
comment: str | dict[str, Any] | None = None,
|
|
937
2063
|
) -> dict[str, Any]:
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
2064
|
+
try:
|
|
2065
|
+
result = service.submit_paper_outline(
|
|
2066
|
+
context.require_quest_root(),
|
|
2067
|
+
mode=mode,
|
|
2068
|
+
outline_id=outline_id,
|
|
2069
|
+
title=title,
|
|
2070
|
+
note=note,
|
|
2071
|
+
story=story,
|
|
2072
|
+
ten_questions=ten_questions,
|
|
2073
|
+
detailed_outline=detailed_outline,
|
|
2074
|
+
review_result=review_result,
|
|
2075
|
+
selected_reason=selected_reason,
|
|
2076
|
+
)
|
|
2077
|
+
return finalize_state_changing_artifact_tool(
|
|
2078
|
+
compact_paper_write_result(result, tool_name="submit_paper_outline"),
|
|
2079
|
+
tool_name="submit_paper_outline",
|
|
2080
|
+
)
|
|
2081
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2082
|
+
return finalize_artifact_tool(
|
|
2083
|
+
_artifact_guided_error_payload(
|
|
2084
|
+
service,
|
|
2085
|
+
context.require_quest_root(),
|
|
2086
|
+
tool_name="submit_paper_outline",
|
|
2087
|
+
exc=exc,
|
|
2088
|
+
),
|
|
2089
|
+
tool_name="submit_paper_outline",
|
|
2090
|
+
)
|
|
951
2091
|
|
|
952
2092
|
@server.tool(
|
|
953
2093
|
name="list_paper_outlines",
|
|
@@ -958,12 +2098,20 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
958
2098
|
annotations=_read_only_tool_annotations(title="List paper outlines"),
|
|
959
2099
|
)
|
|
960
2100
|
def list_paper_outlines(comment: str | dict[str, Any] | None = None) -> dict[str, Any]:
|
|
961
|
-
return
|
|
2101
|
+
return cached_compact_mcp_tool_result(
|
|
2102
|
+
service.list_paper_outlines(context.require_quest_root()),
|
|
2103
|
+
quest_root=context.require_quest_root(),
|
|
2104
|
+
run_id=context.run_id,
|
|
2105
|
+
tool_name="artifact.list_paper_outlines",
|
|
2106
|
+
detail="inventory",
|
|
2107
|
+
cache_key={"detail": "inventory"},
|
|
2108
|
+
reason="artifact_inventory_context_budget",
|
|
2109
|
+
)
|
|
962
2110
|
|
|
963
2111
|
@server.tool(
|
|
964
2112
|
name="submit_paper_bundle",
|
|
965
2113
|
description=(
|
|
966
|
-
"Persist
|
|
2114
|
+
"Persist a paper bundle manifest. Defaults to a draft checkpoint; use package_type='submission_package' only for submission-ready manuscripts."
|
|
967
2115
|
),
|
|
968
2116
|
)
|
|
969
2117
|
def submit_paper_bundle(
|
|
@@ -977,21 +2125,38 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
977
2125
|
compile_report_path: str | None = None,
|
|
978
2126
|
pdf_path: str | None = None,
|
|
979
2127
|
latex_root_path: str | None = None,
|
|
2128
|
+
package_type: str = "draft_checkpoint",
|
|
980
2129
|
comment: str | dict[str, Any] | None = None,
|
|
981
2130
|
) -> dict[str, Any]:
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
2131
|
+
try:
|
|
2132
|
+
result = service.submit_paper_bundle(
|
|
2133
|
+
context.require_quest_root(),
|
|
2134
|
+
title=title,
|
|
2135
|
+
summary=summary,
|
|
2136
|
+
outline_path=outline_path,
|
|
2137
|
+
draft_path=draft_path,
|
|
2138
|
+
writing_plan_path=writing_plan_path,
|
|
2139
|
+
references_path=references_path,
|
|
2140
|
+
claim_evidence_map_path=claim_evidence_map_path,
|
|
2141
|
+
compile_report_path=compile_report_path,
|
|
2142
|
+
pdf_path=pdf_path,
|
|
2143
|
+
latex_root_path=latex_root_path,
|
|
2144
|
+
package_type=package_type,
|
|
2145
|
+
)
|
|
2146
|
+
return finalize_state_changing_artifact_tool(
|
|
2147
|
+
compact_paper_write_result(result, tool_name="submit_paper_bundle"),
|
|
2148
|
+
tool_name="submit_paper_bundle",
|
|
2149
|
+
)
|
|
2150
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2151
|
+
return finalize_artifact_tool(
|
|
2152
|
+
_artifact_guided_error_payload(
|
|
2153
|
+
service,
|
|
2154
|
+
context.require_quest_root(),
|
|
2155
|
+
tool_name="submit_paper_bundle",
|
|
2156
|
+
exc=exc,
|
|
2157
|
+
),
|
|
2158
|
+
tool_name="submit_paper_bundle",
|
|
2159
|
+
)
|
|
995
2160
|
|
|
996
2161
|
@server.tool(
|
|
997
2162
|
name="record_analysis_slice",
|
|
@@ -1050,8 +2215,19 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
1050
2215
|
if comment is not None and "comment" not in enriched:
|
|
1051
2216
|
enriched["comment"] = comment
|
|
1052
2217
|
enriched.setdefault("source", {"kind": "artifact_publish", "quest_id": context.quest_id, "quest_root": str(context.require_quest_root())})
|
|
1053
|
-
|
|
1054
|
-
|
|
2218
|
+
try:
|
|
2219
|
+
result = service.publish_baseline(context.require_quest_root(), enriched)
|
|
2220
|
+
return finalize_state_changing_artifact_tool(result, tool_name="publish_baseline")
|
|
2221
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2222
|
+
return finalize_artifact_tool(
|
|
2223
|
+
_artifact_guided_error_payload(
|
|
2224
|
+
service,
|
|
2225
|
+
context.require_quest_root(),
|
|
2226
|
+
tool_name="publish_baseline",
|
|
2227
|
+
exc=exc,
|
|
2228
|
+
),
|
|
2229
|
+
tool_name="publish_baseline",
|
|
2230
|
+
)
|
|
1055
2231
|
|
|
1056
2232
|
@server.tool(name="attach_baseline", description="Attach a published baseline to the current quest.")
|
|
1057
2233
|
def attach_baseline(
|
|
@@ -1059,14 +2235,27 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
1059
2235
|
variant_id: str | None = None,
|
|
1060
2236
|
comment: str | dict[str, Any] | None = None,
|
|
1061
2237
|
) -> dict[str, Any]:
|
|
1062
|
-
|
|
1063
|
-
|
|
2238
|
+
try:
|
|
2239
|
+
result = service.attach_baseline(context.require_quest_root(), baseline_id, variant_id)
|
|
2240
|
+
return finalize_state_changing_artifact_tool(result, tool_name="attach_baseline")
|
|
2241
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2242
|
+
return finalize_artifact_tool(
|
|
2243
|
+
_artifact_guided_error_payload(
|
|
2244
|
+
service,
|
|
2245
|
+
context.require_quest_root(),
|
|
2246
|
+
tool_name="attach_baseline",
|
|
2247
|
+
exc=exc,
|
|
2248
|
+
),
|
|
2249
|
+
tool_name="attach_baseline",
|
|
2250
|
+
)
|
|
1064
2251
|
|
|
1065
2252
|
@server.tool(
|
|
1066
2253
|
name="confirm_baseline",
|
|
1067
2254
|
description=(
|
|
1068
2255
|
"Confirm the active quest baseline and open the stage gate into idea work. "
|
|
1069
|
-
"The baseline path must point at a quest-local baseline under baselines/local or baselines/imported."
|
|
2256
|
+
"The baseline path must point at a quest-local baseline under baselines/local or baselines/imported. "
|
|
2257
|
+
"Descriptions, derivations, and source refs must live on entries inside "
|
|
2258
|
+
"`metric_contract.metrics`."
|
|
1070
2259
|
),
|
|
1071
2260
|
)
|
|
1072
2261
|
def confirm_baseline(
|
|
@@ -1075,13 +2264,13 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
1075
2264
|
variant_id: str | None = None,
|
|
1076
2265
|
summary: str | None = None,
|
|
1077
2266
|
baseline_kind: str | None = None,
|
|
1078
|
-
metric_contract:
|
|
2267
|
+
metric_contract: MetricContractPayload | None = None,
|
|
1079
2268
|
metric_directions: dict[str, str] | None = None,
|
|
1080
2269
|
metrics_summary: dict[str, Any] | None = None,
|
|
1081
|
-
primary_metric:
|
|
2270
|
+
primary_metric: PrimaryMetricPayload | None = None,
|
|
1082
2271
|
auto_advance: bool = True,
|
|
1083
2272
|
comment: str | dict[str, Any] | None = None,
|
|
1084
|
-
|
|
2273
|
+
) -> dict[str, Any]:
|
|
1085
2274
|
try:
|
|
1086
2275
|
result = service.confirm_baseline(
|
|
1087
2276
|
context.require_quest_root(),
|
|
@@ -1091,16 +2280,156 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
1091
2280
|
variant_id=variant_id,
|
|
1092
2281
|
summary=summary,
|
|
1093
2282
|
baseline_kind=baseline_kind,
|
|
1094
|
-
metric_contract=metric_contract,
|
|
2283
|
+
metric_contract=metric_contract.model_dump(exclude_none=True) if metric_contract is not None else None,
|
|
1095
2284
|
metric_directions=metric_directions,
|
|
1096
2285
|
metrics_summary=metrics_summary,
|
|
1097
|
-
primary_metric=primary_metric,
|
|
2286
|
+
primary_metric=primary_metric.model_dump(exclude_none=True) if primary_metric is not None else None,
|
|
1098
2287
|
auto_advance=auto_advance,
|
|
1099
2288
|
strict_metric_contract=True,
|
|
1100
2289
|
)
|
|
1101
2290
|
return finalize_state_changing_artifact_tool(result, tool_name="confirm_baseline")
|
|
1102
2291
|
except MetricContractValidationError as exc:
|
|
1103
2292
|
return _metric_validation_error_payload(exc)
|
|
2293
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2294
|
+
return finalize_artifact_tool(
|
|
2295
|
+
_artifact_guided_error_payload(
|
|
2296
|
+
service,
|
|
2297
|
+
context.require_quest_root(),
|
|
2298
|
+
tool_name="confirm_baseline",
|
|
2299
|
+
exc=exc,
|
|
2300
|
+
),
|
|
2301
|
+
tool_name="confirm_baseline",
|
|
2302
|
+
)
|
|
2303
|
+
|
|
2304
|
+
@server.tool(
|
|
2305
|
+
name="overwrite_baseline",
|
|
2306
|
+
description=(
|
|
2307
|
+
"Refresh an already accepted baseline after verified code, variant, or canonical metric changes. "
|
|
2308
|
+
"This rewrites the active baseline reference and downstream inventories, so comparator-breaking changes "
|
|
2309
|
+
"should usually become a new baseline id or variant instead of an in-place overwrite."
|
|
2310
|
+
),
|
|
2311
|
+
)
|
|
2312
|
+
def overwrite_baseline(
|
|
2313
|
+
change_summary: str,
|
|
2314
|
+
baseline_id: str | None = None,
|
|
2315
|
+
baseline_path: str | None = None,
|
|
2316
|
+
variant_id: str | None = None,
|
|
2317
|
+
summary: str | None = None,
|
|
2318
|
+
baseline_kind: str | None = None,
|
|
2319
|
+
metric_contract: MetricContractPayload | None = None,
|
|
2320
|
+
metric_directions: dict[str, str] | None = None,
|
|
2321
|
+
metrics_summary: dict[str, Any] | None = None,
|
|
2322
|
+
primary_metric: PrimaryMetricPayload | None = None,
|
|
2323
|
+
supplementary_baselines: list[SupplementaryBaselinePayload] | None = None,
|
|
2324
|
+
overwrite_scope: str = "full_refresh",
|
|
2325
|
+
allow_path_change: bool = False,
|
|
2326
|
+
allow_protocol_breaking_change: bool = False,
|
|
2327
|
+
sync_requested_baseline_ref: bool = True,
|
|
2328
|
+
refresh_analysis_inventory: bool = True,
|
|
2329
|
+
refresh_paper_inventory: bool = True,
|
|
2330
|
+
auto_advance: bool = True,
|
|
2331
|
+
comment: str | dict[str, Any] | None = None,
|
|
2332
|
+
) -> dict[str, Any]:
|
|
2333
|
+
try:
|
|
2334
|
+
result = service.overwrite_baseline(
|
|
2335
|
+
context.require_quest_root(),
|
|
2336
|
+
baseline_id=baseline_id,
|
|
2337
|
+
baseline_path=baseline_path,
|
|
2338
|
+
variant_id=variant_id,
|
|
2339
|
+
summary=summary,
|
|
2340
|
+
change_summary=change_summary,
|
|
2341
|
+
baseline_kind=baseline_kind,
|
|
2342
|
+
metric_contract=metric_contract.model_dump(exclude_none=True) if metric_contract is not None else None,
|
|
2343
|
+
metric_directions=metric_directions,
|
|
2344
|
+
metrics_summary=metrics_summary,
|
|
2345
|
+
primary_metric=primary_metric.model_dump(exclude_none=True) if primary_metric is not None else None,
|
|
2346
|
+
supplementary_baselines=[
|
|
2347
|
+
item.model_dump(exclude_none=True) for item in (supplementary_baselines or [])
|
|
2348
|
+
]
|
|
2349
|
+
or None,
|
|
2350
|
+
overwrite_scope=overwrite_scope,
|
|
2351
|
+
allow_path_change=allow_path_change,
|
|
2352
|
+
allow_protocol_breaking_change=allow_protocol_breaking_change,
|
|
2353
|
+
sync_requested_baseline_ref=sync_requested_baseline_ref,
|
|
2354
|
+
refresh_analysis_inventory=refresh_analysis_inventory,
|
|
2355
|
+
refresh_paper_inventory=refresh_paper_inventory,
|
|
2356
|
+
auto_advance=auto_advance,
|
|
2357
|
+
strict_metric_contract=True,
|
|
2358
|
+
comment=comment,
|
|
2359
|
+
)
|
|
2360
|
+
return finalize_state_changing_artifact_tool(result, tool_name="overwrite_baseline")
|
|
2361
|
+
except MetricContractValidationError as exc:
|
|
2362
|
+
return _metric_validation_error_payload(exc)
|
|
2363
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2364
|
+
return finalize_artifact_tool(
|
|
2365
|
+
_artifact_guided_error_payload(
|
|
2366
|
+
service,
|
|
2367
|
+
context.require_quest_root(),
|
|
2368
|
+
tool_name="overwrite_baseline",
|
|
2369
|
+
exc=exc,
|
|
2370
|
+
),
|
|
2371
|
+
tool_name="overwrite_baseline",
|
|
2372
|
+
)
|
|
2373
|
+
|
|
2374
|
+
@server.tool(
|
|
2375
|
+
name="overwrite_baseline",
|
|
2376
|
+
description=(
|
|
2377
|
+
"Refresh an already accepted baseline after verified code, variant, or canonical metric changes. "
|
|
2378
|
+
"This rewrites the active baseline reference and downstream inventories, so comparator-breaking changes "
|
|
2379
|
+
"should usually become a new baseline id or variant instead of an in-place overwrite."
|
|
2380
|
+
),
|
|
2381
|
+
)
|
|
2382
|
+
def overwrite_baseline(
|
|
2383
|
+
change_summary: str,
|
|
2384
|
+
baseline_id: str | None = None,
|
|
2385
|
+
baseline_path: str | None = None,
|
|
2386
|
+
variant_id: str | None = None,
|
|
2387
|
+
summary: str | None = None,
|
|
2388
|
+
baseline_kind: str | None = None,
|
|
2389
|
+
metric_contract: MetricContractPayload | None = None,
|
|
2390
|
+
metric_directions: dict[str, str] | None = None,
|
|
2391
|
+
metrics_summary: dict[str, Any] | None = None,
|
|
2392
|
+
primary_metric: PrimaryMetricPayload | None = None,
|
|
2393
|
+
supplementary_baselines: list[SupplementaryBaselinePayload] | None = None,
|
|
2394
|
+
overwrite_scope: str = "full_refresh",
|
|
2395
|
+
allow_path_change: bool = False,
|
|
2396
|
+
allow_protocol_breaking_change: bool = False,
|
|
2397
|
+
sync_requested_baseline_ref: bool = True,
|
|
2398
|
+
refresh_analysis_inventory: bool = True,
|
|
2399
|
+
refresh_paper_inventory: bool = True,
|
|
2400
|
+
auto_advance: bool = True,
|
|
2401
|
+
comment: str | dict[str, Any] | None = None,
|
|
2402
|
+
) -> dict[str, Any]:
|
|
2403
|
+
try:
|
|
2404
|
+
result = service.overwrite_baseline(
|
|
2405
|
+
context.require_quest_root(),
|
|
2406
|
+
baseline_id=baseline_id,
|
|
2407
|
+
baseline_path=baseline_path,
|
|
2408
|
+
variant_id=variant_id,
|
|
2409
|
+
summary=summary,
|
|
2410
|
+
change_summary=change_summary,
|
|
2411
|
+
baseline_kind=baseline_kind,
|
|
2412
|
+
metric_contract=metric_contract.model_dump(exclude_none=True) if metric_contract is not None else None,
|
|
2413
|
+
metric_directions=metric_directions,
|
|
2414
|
+
metrics_summary=metrics_summary,
|
|
2415
|
+
primary_metric=primary_metric.model_dump(exclude_none=True) if primary_metric is not None else None,
|
|
2416
|
+
supplementary_baselines=[
|
|
2417
|
+
item.model_dump(exclude_none=True) for item in (supplementary_baselines or [])
|
|
2418
|
+
]
|
|
2419
|
+
or None,
|
|
2420
|
+
overwrite_scope=overwrite_scope,
|
|
2421
|
+
allow_path_change=allow_path_change,
|
|
2422
|
+
allow_protocol_breaking_change=allow_protocol_breaking_change,
|
|
2423
|
+
sync_requested_baseline_ref=sync_requested_baseline_ref,
|
|
2424
|
+
refresh_analysis_inventory=refresh_analysis_inventory,
|
|
2425
|
+
refresh_paper_inventory=refresh_paper_inventory,
|
|
2426
|
+
auto_advance=auto_advance,
|
|
2427
|
+
strict_metric_contract=True,
|
|
2428
|
+
comment=comment,
|
|
2429
|
+
)
|
|
2430
|
+
return finalize_state_changing_artifact_tool(result, tool_name="overwrite_baseline")
|
|
2431
|
+
except MetricContractValidationError as exc:
|
|
2432
|
+
return _metric_validation_error_payload(exc)
|
|
1104
2433
|
|
|
1105
2434
|
@server.tool(
|
|
1106
2435
|
name="waive_baseline",
|
|
@@ -1111,13 +2440,24 @@ def build_artifact_server(context: McpContext) -> FastMCP:
|
|
|
1111
2440
|
auto_advance: bool = True,
|
|
1112
2441
|
comment: str | dict[str, Any] | None = None,
|
|
1113
2442
|
) -> dict[str, Any]:
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
2443
|
+
try:
|
|
2444
|
+
result = service.waive_baseline(
|
|
2445
|
+
context.require_quest_root(),
|
|
2446
|
+
reason=reason,
|
|
2447
|
+
comment=comment,
|
|
2448
|
+
auto_advance=auto_advance,
|
|
2449
|
+
)
|
|
2450
|
+
return finalize_state_changing_artifact_tool(result, tool_name="waive_baseline")
|
|
2451
|
+
except (ValueError, FileNotFoundError, RuntimeError) as exc:
|
|
2452
|
+
return finalize_artifact_tool(
|
|
2453
|
+
_artifact_guided_error_payload(
|
|
2454
|
+
service,
|
|
2455
|
+
context.require_quest_root(),
|
|
2456
|
+
tool_name="waive_baseline",
|
|
2457
|
+
exc=exc,
|
|
2458
|
+
),
|
|
2459
|
+
tool_name="waive_baseline",
|
|
2460
|
+
)
|
|
1121
2461
|
|
|
1122
2462
|
@server.tool(
|
|
1123
2463
|
name="arxiv",
|
|
@@ -1248,7 +2588,8 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1248
2588
|
name="bash_exec",
|
|
1249
2589
|
description=(
|
|
1250
2590
|
"Execute a bash command inside the current quest. "
|
|
1251
|
-
"mode=detach returns immediately. mode=await/create waits for completion
|
|
2591
|
+
"mode=detach returns immediately. mode=await/create waits for completion up to a bounded wait window, "
|
|
2592
|
+
"then returns a running-session notice if the command is still active. "
|
|
1252
2593
|
"mode=read returns the saved log. It returns the full saved log up to 2000 lines, "
|
|
1253
2594
|
"or a 500-line head plus 1500-line tail preview for longer logs. "
|
|
1254
2595
|
"Use start/tail for rendered line windows and tail_limit/after_seq for seq-based monitoring. "
|
|
@@ -1257,7 +2598,7 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1257
2598
|
),
|
|
1258
2599
|
)
|
|
1259
2600
|
def bash_exec(
|
|
1260
|
-
command:
|
|
2601
|
+
command: Any = "",
|
|
1261
2602
|
mode: str = "detach",
|
|
1262
2603
|
id: str | None = None,
|
|
1263
2604
|
reason: str | None = None,
|
|
@@ -1266,6 +2607,7 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1266
2607
|
export_log: bool = False,
|
|
1267
2608
|
export_log_to: str | None = None,
|
|
1268
2609
|
timeout_seconds: int | None = None,
|
|
2610
|
+
wait_timeout_seconds: int | None = None,
|
|
1269
2611
|
status: str | None = None,
|
|
1270
2612
|
kind: str | None = None,
|
|
1271
2613
|
agent_ids: list[str] | None = None,
|
|
@@ -1286,6 +2628,28 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1286
2628
|
quest_root = context.require_quest_root().resolve()
|
|
1287
2629
|
|
|
1288
2630
|
def finalize(payload: dict[str, Any]) -> dict[str, Any]:
|
|
2631
|
+
if normalized_mode == "read":
|
|
2632
|
+
bash_id = str(payload.get("bash_id") or payload.get("id") or id or "")
|
|
2633
|
+
payload = cached_compact_mcp_tool_result(
|
|
2634
|
+
payload,
|
|
2635
|
+
quest_root=quest_root,
|
|
2636
|
+
run_id=context.run_id,
|
|
2637
|
+
tool_name="bash_exec.bash_exec",
|
|
2638
|
+
detail="read",
|
|
2639
|
+
cache_key={
|
|
2640
|
+
"mode": "read",
|
|
2641
|
+
"bash_id": bash_id,
|
|
2642
|
+
"start": start,
|
|
2643
|
+
"tail": tail,
|
|
2644
|
+
"tail_limit": tail_limit,
|
|
2645
|
+
"before_seq": before_seq,
|
|
2646
|
+
"after_seq": after_seq,
|
|
2647
|
+
"order": order,
|
|
2648
|
+
"include_log": include_log,
|
|
2649
|
+
},
|
|
2650
|
+
source_path=service.terminal_log_path(quest_root, bash_id) if bash_id else None,
|
|
2651
|
+
reason="bash_exec_read_context_budget",
|
|
2652
|
+
)
|
|
1289
2653
|
quest_service.record_tool_activity(
|
|
1290
2654
|
quest_root,
|
|
1291
2655
|
tool_name=f"bash_exec.{normalized_mode}",
|
|
@@ -1298,6 +2662,35 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1298
2662
|
normalized_mode = "await"
|
|
1299
2663
|
if normalized_mode not in {"detach", "await", "read", "kill", "list", "history"}:
|
|
1300
2664
|
raise ValueError("Mode must be one of `detach`, `await`, `create`, `read`, `kill`, `list`, or `history`.")
|
|
2665
|
+
normalized_command = _normalize_bash_exec_command_input(command)
|
|
2666
|
+
normalized_timeout_seconds = _normalize_positive_timeout_seconds(
|
|
2667
|
+
timeout_seconds,
|
|
2668
|
+
field_name="timeout_seconds",
|
|
2669
|
+
)
|
|
2670
|
+
normalized_wait_timeout_seconds = _normalize_positive_timeout_seconds(
|
|
2671
|
+
wait_timeout_seconds,
|
|
2672
|
+
field_name="wait_timeout_seconds",
|
|
2673
|
+
)
|
|
2674
|
+
|
|
2675
|
+
def build_await_payload(session: dict[str, Any], *, wait_timeout: int | None) -> dict[str, Any]:
|
|
2676
|
+
payload = service.build_tool_result(
|
|
2677
|
+
context,
|
|
2678
|
+
session=session,
|
|
2679
|
+
include_log=False,
|
|
2680
|
+
export_log=export_log,
|
|
2681
|
+
export_log_to=export_log_to,
|
|
2682
|
+
)
|
|
2683
|
+
session_status = str(session.get("status") or "").strip().lower()
|
|
2684
|
+
if wait_timeout is not None and session_status not in BASH_EXEC_TERMINAL_STATUSES:
|
|
2685
|
+
payload.update(
|
|
2686
|
+
_build_bash_exec_wait_notice(
|
|
2687
|
+
bash_id=str(session["bash_id"]),
|
|
2688
|
+
wait_timeout_seconds=wait_timeout,
|
|
2689
|
+
status=session_status,
|
|
2690
|
+
)
|
|
2691
|
+
)
|
|
2692
|
+
return payload
|
|
2693
|
+
|
|
1301
2694
|
if normalized_mode in {"list", "history"}:
|
|
1302
2695
|
resolved_limit = 500 if normalized_mode == "history" and limit == 20 else max(1, min(limit, 500))
|
|
1303
2696
|
items = service.list_sessions(
|
|
@@ -1356,7 +2749,7 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1356
2749
|
tail=tail if tail is not None else tail_limit,
|
|
1357
2750
|
)
|
|
1358
2751
|
)
|
|
1359
|
-
return finalize(payload)
|
|
2752
|
+
return finalize(_attach_bash_log_truncation_metadata(payload))
|
|
1360
2753
|
use_tail = tail_limit is not None or before_seq is not None or after_seq is not None or normalized_order != "asc"
|
|
1361
2754
|
if use_tail:
|
|
1362
2755
|
resolved_tail_limit = max(1, min(int(tail_limit or 200), 1000))
|
|
@@ -1383,6 +2776,39 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1383
2776
|
payload["after_seq"] = tail_meta.get("after_seq")
|
|
1384
2777
|
payload["before_seq"] = tail_meta.get("before_seq")
|
|
1385
2778
|
payload["order"] = normalized_order
|
|
2779
|
+
visible_seqs = [int(entry.get("seq") or 0) for entry in entries if int(entry.get("seq") or 0) > 0]
|
|
2780
|
+
seq_window_start = min(visible_seqs) if visible_seqs else None
|
|
2781
|
+
seq_window_end = max(visible_seqs) if visible_seqs else None
|
|
2782
|
+
latest_seq_value = tail_meta.get("latest_seq")
|
|
2783
|
+
seqs_before_window = max(int(seq_window_start or 0) - 1, 0) if seq_window_start is not None else None
|
|
2784
|
+
seqs_after_window = (
|
|
2785
|
+
max(int(latest_seq_value or 0) - int(seq_window_end or 0), 0)
|
|
2786
|
+
if seq_window_end is not None and latest_seq_value is not None
|
|
2787
|
+
else None
|
|
2788
|
+
)
|
|
2789
|
+
payload["seq_window_start"] = seq_window_start
|
|
2790
|
+
payload["seq_window_end"] = seq_window_end
|
|
2791
|
+
payload["seq_has_more_before"] = bool(seqs_before_window and seqs_before_window > 0)
|
|
2792
|
+
payload["seq_has_more_after"] = bool(seqs_after_window and seqs_after_window > 0)
|
|
2793
|
+
payload["seqs_before_window"] = seqs_before_window
|
|
2794
|
+
payload["seqs_after_window"] = seqs_after_window
|
|
2795
|
+
payload["tail_is_partial"] = payload["seq_has_more_before"] or payload["seq_has_more_after"]
|
|
2796
|
+
if payload["tail_is_partial"]:
|
|
2797
|
+
before_text = (
|
|
2798
|
+
f"{seqs_before_window} seq(s) before"
|
|
2799
|
+
if seqs_before_window is not None
|
|
2800
|
+
else "some earlier seqs outside this filtered window"
|
|
2801
|
+
)
|
|
2802
|
+
after_text = (
|
|
2803
|
+
f"{seqs_after_window} seq(s) after"
|
|
2804
|
+
if seqs_after_window is not None
|
|
2805
|
+
else "some later seqs outside this filtered window"
|
|
2806
|
+
)
|
|
2807
|
+
payload["log_truncation_notice"] = (
|
|
2808
|
+
"This seq-based bash_exec read is only a partial window, not the full log. "
|
|
2809
|
+
f"It currently covers seq {seq_window_start} to {seq_window_end}; there are {before_text} and {after_text}. "
|
|
2810
|
+
"Continue with before_seq / after_seq or adjust tail_limit if you need more surrounding output."
|
|
2811
|
+
)
|
|
1386
2812
|
return finalize(payload)
|
|
1387
2813
|
payload = service.build_tool_result(
|
|
1388
2814
|
context,
|
|
@@ -1392,7 +2818,7 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1392
2818
|
export_log_to=export_log_to,
|
|
1393
2819
|
)
|
|
1394
2820
|
payload.update(_build_default_bash_log_payload_from_path(service.terminal_log_path(quest_root, bash_id)))
|
|
1395
|
-
return finalize(payload)
|
|
2821
|
+
return finalize(_attach_bash_log_truncation_metadata(payload))
|
|
1396
2822
|
if normalized_mode == "kill":
|
|
1397
2823
|
bash_id = service.resolve_session_id(quest_root, id)
|
|
1398
2824
|
session = service.request_stop(
|
|
@@ -1403,39 +2829,41 @@ def build_bash_exec_server(context: McpContext) -> FastMCP:
|
|
|
1403
2829
|
force=force,
|
|
1404
2830
|
)
|
|
1405
2831
|
if wait:
|
|
1406
|
-
|
|
2832
|
+
resolved_wait_timeout = normalized_wait_timeout_seconds or normalized_timeout_seconds
|
|
2833
|
+
session = service.wait_for_session(quest_root, bash_id, timeout_seconds=resolved_wait_timeout)
|
|
1407
2834
|
return finalize(service.build_tool_result(context, session=session, include_log=False))
|
|
1408
|
-
if normalized_mode == "await" and not
|
|
2835
|
+
if normalized_mode == "await" and not normalized_command:
|
|
1409
2836
|
bash_id = service.resolve_session_id(quest_root, id)
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
if not (command or "").strip():
|
|
2837
|
+
resolved_wait_timeout = (
|
|
2838
|
+
normalized_wait_timeout_seconds
|
|
2839
|
+
or normalized_timeout_seconds
|
|
2840
|
+
or DEFAULT_BASH_EXEC_AWAIT_WAIT_TIMEOUT_SECONDS
|
|
2841
|
+
)
|
|
2842
|
+
session = service.wait_for_session(quest_root, bash_id, timeout_seconds=resolved_wait_timeout)
|
|
2843
|
+
return finalize(build_await_payload(session, wait_timeout=resolved_wait_timeout))
|
|
2844
|
+
if not normalized_command.strip():
|
|
1419
2845
|
raise ValueError("command is required for `detach` and `await`.")
|
|
1420
2846
|
session = service.start_session(
|
|
1421
2847
|
context,
|
|
1422
|
-
command=
|
|
2848
|
+
command=normalized_command,
|
|
1423
2849
|
mode=normalized_mode,
|
|
1424
2850
|
workdir=workdir,
|
|
1425
2851
|
env=env,
|
|
1426
|
-
timeout_seconds=
|
|
2852
|
+
timeout_seconds=normalized_timeout_seconds,
|
|
1427
2853
|
comment=comment,
|
|
1428
2854
|
)
|
|
1429
2855
|
if normalized_mode == "detach":
|
|
1430
2856
|
return finalize(service.build_tool_result(context, session=session, include_log=False))
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
2857
|
+
resolved_wait_timeout = (
|
|
2858
|
+
normalized_wait_timeout_seconds
|
|
2859
|
+
or DEFAULT_BASH_EXEC_AWAIT_WAIT_TIMEOUT_SECONDS
|
|
2860
|
+
)
|
|
2861
|
+
session = service.wait_for_session(
|
|
2862
|
+
quest_root,
|
|
2863
|
+
str(session["bash_id"]),
|
|
2864
|
+
timeout_seconds=resolved_wait_timeout,
|
|
2865
|
+
)
|
|
2866
|
+
return finalize(build_await_payload(session, wait_timeout=resolved_wait_timeout))
|
|
1439
2867
|
|
|
1440
2868
|
return server
|
|
1441
2869
|
|
|
@@ -1458,7 +2886,19 @@ def _resolve_search_scope(context: McpContext, scope: str) -> str:
|
|
|
1458
2886
|
return normalized
|
|
1459
2887
|
|
|
1460
2888
|
|
|
2889
|
+
def _ensure_utf8_stdio() -> None:
|
|
2890
|
+
for stream in (sys.stdin, sys.stdout, sys.stderr):
|
|
2891
|
+
reconfigure = getattr(stream, "reconfigure", None)
|
|
2892
|
+
if not callable(reconfigure):
|
|
2893
|
+
continue
|
|
2894
|
+
try:
|
|
2895
|
+
reconfigure(encoding="utf-8", errors="replace")
|
|
2896
|
+
except Exception:
|
|
2897
|
+
continue
|
|
2898
|
+
|
|
2899
|
+
|
|
1461
2900
|
def main() -> int:
|
|
2901
|
+
_ensure_utf8_stdio()
|
|
1462
2902
|
parser = argparse.ArgumentParser(description="DeepScientist built-in MCP server")
|
|
1463
2903
|
parser.add_argument("--namespace", choices=("memory", "artifact", "bash_exec"), required=True)
|
|
1464
2904
|
args = parser.parse_args()
|