@furongjun1999/dsh-memory 0.4.11 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +552 -465
- package/codebuddy/CODEBUDDY.md +11 -3
- package/codebuddy/README.md +92 -90
- package/codebuddy/mcp.json +27 -27
- package/docs/GBrain/345/217/257/345/200/237/351/211/264/347/202/271_/347/201/265/346/236/242/350/220/275/347/202/271/344/272/244/346/216/245_20260919.md +169 -169
- package/docs/Pi/345/217/257/345/255/246/344/271/240/344/274/230/347/202/271_/347/201/265/346/236/242/345/244/247/350/204/221/346/224/271/350/277/233/344/272/244/346/216/245_20260915.md +144 -144
- package/docs/README.md +143 -111
- package/docs/discipline/harnesses.yaml +244 -226
- package/docs/discipline/templates/full.md.tmpl +61 -61
- package/docs/discipline/templates/rules.mdc.tmpl +68 -0
- package/docs/discipline/templates/skill.md.tmpl +23 -23
- package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v1.0.md +299 -299
- package/docs/eval/AGI/344/270/203/347/273/264/350/257/204/345/210/206/346/212/245/345/221/212_md_cg_v2.0.md +239 -239
- package/docs/eval/bench_lingshu_self/bench_self.py +140 -0
- package/docs/eval/bench_lingshu_self/self_bench_result.json +404 -0
- package/docs/eval/bench_lingshu_self//347/201/265/346/236/242/350/207/252/345/272/223/347/253/257/345/210/260/347/253/257/346/243/200/347/264/242/345/256/236/346/265/213_v1.0.md +38 -0
- package/docs/eval//344/270/215/345/217/257/351/235/240/346/200/247/350/220/275/345/234/260_P0_v1.0.md +185 -0
- package/docs/eval//345/256/236/351/252/214/346/226/271/346/241/210_/345/255/246/344/271/240/351/227/255/347/216/257AB/344/270/216/346/250/252/350/257/204_v1.0.md +174 -174
- package/docs/eval//346/225/205/351/232/234/346/263/250/345/205/245/345/256/236/346/265/213_v1.0.md +422 -0
- package/docs/eval//346/250/252/350/257/204_/345/205/255/345/256/266100/351/242/230/344/270/255/350/213/261/345/217/214/346/237/245_v1.0.md +223 -223
- package/docs/eval//347/253/257/345/210/260/347/253/257LoCoMoQA/345/220/214/345/217/243/345/276/204/345/257/271/347/205/247_v1.0.md +100 -0
- package/docs/eval//347/253/257/345/210/260/347/253/257/345/271/262/346/211/260/346/261/240/350/257/204/346/265/213_/347/241/256/345/256/232/346/200/247/350/243/201/345/206/263vsLLM_judge_v1.1.md +197 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v1.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v10.md +210 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v11.md +227 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v12.md +203 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v13.md +233 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v14.md +191 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v15.md +213 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v16.md +214 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v17.md +199 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v2.md +156 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v3.md +152 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v4.md +128 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v5.md +114 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v6.md +192 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v7.md +187 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v8.md +207 -0
- package/docs/eval//347/274/272/351/231/267/346/214/226/346/216/230_/350/207/252/344/270/273/350/277/255/344/273/243_v9.md +203 -0
- package/docs/{mdcg → hive}//344/273/244/347/211/214/344/270/216/350/247/222/350/211/262/346/235/203/350/201/214/345/210/206/347/246/273_v0.1.md +165 -160
- package/docs/hive//344/273/244/347/211/214/350/257/255/344/271/211/344/277/256/346/255/243_/344/273/262/350/243/201/344/275/215_v0.1.md +76 -0
- package/docs/{mdcg → hive}//345/255/220/344/273/243/347/220/206/351/205/215/347/275/256/346/240/207/345/207/206_v0.5.md +236 -236
- package/docs/hive//345/256/211/345/205/250/345/256/241/350/256/241/345/256/236/351/224/232_v0.1.md +202 -0
- package/docs/hive//346/243/200/347/264/242/346/224/266/346/225/233/345/256/236/346/265/213/344/270/216S1b/350/256/276/350/256/241_v0.1.md +43 -43
- package/docs/hive//346/243/200/347/264/242/347/256/227/346/263/225/345/217/243/345/276/204/345/257/271/347/205/247_v0.1.md +85 -0
- package/docs/hive//346/243/200/347/264/242/350/267/257/345/276/204/344/270/216/350/256/244/347/237/245/347/273/223/346/236/204/345/245/221/347/272/246_v0.1.md +102 -102
- package/docs/hive//350/234/202/345/267/242M6_ingest/345/256/236/346/226/275/350/256/241/345/210/222_v0.1.md +47 -0
- package/docs/hive//350/234/202/345/267/242/345/217/214/345/256/236/344/276/213/344/272/222/351/252/214_/350/256/276/350/256/241/345/256/232/347/250/277.md +519 -503
- package/docs/hive//350/234/202/345/267/242/345/267/245/344/275/234/350/256/260/345/277/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +85 -85
- package/docs/hive//350/234/202/345/267/242/350/256/276/350/256/241_/347/220/206/350/256/272/345/257/271/351/275/220_v0.1.md +191 -0
- package/docs/hive//350/234/202/345/267/242/350/277/255/344/273/243_/345/256/217/350/247/202/344/270/216/347/276/244/344/275/223/350/260/203/345/272/246_v0.1.md +90 -0
- package/docs/images/lingshu-moonlight-covenant-poster-preview.jpg +0 -0
- package/docs/images/lingshu-moonlight-covenant-poster.png +0 -0
- package/docs/mdcg/D_meta_/345/267/245/347/250/213/345/214/226/346/226/271/346/241/210_v0.2.md +216 -216
- package/docs/mdcg/README/350/257/246/347/273/206/347/211/210_v0.4.10.md +646 -646
- package/docs/mdcg/lingshu_tutorial.html +14449 -14449
- package/docs/mdcg/release_v0.4.11.md +49 -0
- package/docs/mdcg/release_v0.4.5.md +55 -55
- package/docs/mdcg/tool_table_v0.3.0.md +117 -117
- package/docs/mdcg//345/205/250/345/272/223/344/273/243/347/240/201/350/257/204/345/256/241/344/270/216/346/235/241/344/273/266/345/214/226/346/263/250/351/207/212_/350/256/241/345/210/222_v0.1.md +600 -600
- package/docs/mdcg//345/212/237/350/203/275/350/260/203/347/224/250/346/230/240/345/260/204/350/241/250_v0.1.md +40 -40
- package/docs/mdcg//345/215/225/345/205/203/350/207/252/346/210/221/351/224/232/347/202/271_/347/263/273/347/273/237/346/217/220/347/244/272/350/257/215/346/240/207/345/207/206_v0.3.md +275 -275
- package/docs/mdcg//345/217/221/345/270/203/351/227/250/347/246/201/351/223/276_v0.1.md +54 -0
- package/docs/mdcg//346/272/220/347/240/201/347/272/247/346/236/266/346/236/204/345/256/241/350/256/241_GPT/346/211/271/350/257/204/345/257/271/347/205/247_v1.0.md +130 -130
- package/docs/mdcg//347/201/265/346/236/24282/345/267/245/345/205/267_/345/212/237/350/203/275/346/225/264/347/220/206/344/270/216/350/277/201/347/247/273/346/230/240/345/260/204_v0.1.md +278 -278
- package/docs/mdcg//347/201/265/346/236/242/350/256/260/345/277/206/345/212/250/350/257/215/345/215/217/350/256/256_v1.0-draft.md +172 -172
- package/docs/mdcg//347/274/272/345/217/243/345/215/225_P0/346/224/266/345/217/243_v0.1.md +270 -270
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_G4-G8/347/274/272/345/217/243/350/243/201/345/256/232/345/215/225_v0.1.md +491 -491
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/346/235/241/344/273/266/347/251/272/351/227/264/345/220/210/346/210/220/344/270/216/347/224/237/346/225/210/346/235/241/344/273/266/345/217/243/345/276/204_v0.1.md +340 -340
- package/docs/mdcg//350/256/244/347/237/245/345/233/276_/347/264/242/345/274/225/344/270/216/345/267/245/347/250/213/350/247/204/350/214/203/345/214/226_/350/256/241/345/210/222_v0.1.md +588 -588
- package/docs/plans/GridWorld/346/234/200/345/260/217/351/227/255/347/216/257/350/247/204/346/240/274_v0.1.md +176 -176
- package/docs/plans//345/221/275/345/220/215/346/262/273/347/220/206_/351/241/271/347/233/256/350/256/241/345/210/222.md +81 -81
- package/docs/swarm//350/234/202/347/276/244/344/272/222/350/201/224_v0.1.md +704 -704
- package/docs/swarm//350/234/202/347/276/244/345/220/214/351/224/231/346/243/200/346/265/213/345/256/236/351/252/214/345/215/217/350/256/256_v0.1.md +242 -242
- package/docs/theory//344/270/215/345/217/257/351/235/240/345/256/232/347/220/206/344/270/216/345/244/261/346/225/210/344/274/230/345/205/210/346/241/206/346/236/266_v0.3.md +365 -0
- package/docs/theory//345/215/225/347/272/277/347/250/213/344/270/216/346/263/250/346/204/217/345/212/233/351/233/206/344/270/255_/346/227/240/344/272/211/350/256/256/347/220/206/350/256/272/346/226/207/346/241/243_v1.0.md +129 -129
- package/docs/theory//345/271/266/345/217/221/345/277/205/347/204/266/346/200/247/347/220/206/350/256/272_v0.2.md +134 -134
- package/docs/theory//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/docs/theory//346/246/202/345/277/265/345/210/206/345/261/202/345/257/271/351/275/220/350/241/250_v0.1.md +145 -145
- package/docs/theory//347/220/206/350/256/272_/346/234/272/345/210/266_/344/273/243/347/240/201_/345/256/236/351/252/214_/347/274/272/345/217/243/347/237/251/351/230/265_v0.1.md +144 -144
- package/docs/theory//347/220/206/350/256/272/344/273/223/346/213/206/345/210/206/344/270/216/347/231/275/347/256/261/347/237/245/350/257/206/345/272/223/345/206/205/350/277/201_v0.1.md +198 -198
- package/docs/theory//350/256/244/347/237/245/344/273/243/347/220/206/344/270/216/346/224/266/346/225/233/347/273/223/346/236/204_/346/235/241/344/273/266/350/256/272/351/207/215/346/236/204_v0.1.md +221 -221
- package/docs/world_model//344/270/226/347/225/214/346/250/241/345/236/213_/347/245/236/347/273/217/347/275/221/347/273/234/345/272/225/345/261/202/346/236/266/346/236/204_v1.0.md +237 -237
- package/docs//344/270/215/345/217/257/351/235/240/346/200/247/347/220/206/350/256/272_v0.1.md +343 -0
- package/docs//345/217/221/345/270/203/344/273/266/345/233/236/346/272/257/350/257/264/346/230/216_v0.1.md +82 -82
- package/docs//345/267/245/344/275/234/347/272/252/345/276/213_/350/256/244/347/237/245/345/233/276/346/235/241/347/233/256_v1.1.json +28 -2
- package/dsh/README.md +82 -82
- package/dsh/cordis.yml.example +139 -139
- package/dsh/update-lingshu.bat +11 -11
- package/lib/bridge.d.ts +9 -0
- package/lib/bridge.js +35 -0
- package/lib/hooks.js +36 -2
- package/lib/index.js +7 -1
- package/lib/lib/roleplay_web.js +116 -29
- package/lib/lib/token_store.d.ts +7 -1
- package/lib/lib/token_store.js +12 -3
- package/md_cg/__init__.py +7 -7
- package/md_cg/audit.py +379 -368
- package/md_cg/autonomy.py +287 -287
- package/md_cg/backfill.py +1328 -1327
- package/md_cg/backfill_bigdomain.py +34 -34
- package/md_cg/backfill_bucket_zh.py +35 -0
- package/md_cg/bench6_arms.py +410 -410
- package/md_cg/bench6_common.py +230 -230
- package/md_cg/bench6_competitors.py +212 -212
- package/md_cg/bench_axis_domain.py +257 -257
- package/md_cg/bench_blind_comp.py +308 -308
- package/md_cg/bench_e2e_judge.py +532 -0
- package/md_cg/bench_e2e_locomo_qa.py +368 -0
- package/md_cg/bench_e2e_qa.py +256 -0
- package/md_cg/bench_en_atoms_public.py +230 -230
- package/md_cg/bench_governance.py +348 -348
- package/md_cg/bench_lme_zh.py +410 -410
- package/md_cg/bench_locomo.py +121 -121
- package/md_cg/bench_locomo_zh.py +450 -450
- package/md_cg/bench_locomo_zh_public.py +147 -147
- package/md_cg/bench_longmem.py +112 -112
- package/md_cg/bench_membench.py +632 -632
- package/md_cg/bench_p0.py +149 -149
- package/md_cg/bench_progressive.py +287 -287
- package/md_cg/bench_role_views.py +238 -238
- package/md_cg/bench_task_ab.py +243 -243
- package/md_cg/bench_task_ab_llm.py +408 -408
- package/md_cg/bench_unified_en.py +204 -204
- package/md_cg/bench_zh_mad.py +601 -601
- package/md_cg/blindspot_tickets.py +123 -123
- package/md_cg/branches.py +301 -285
- package/md_cg/build_postings.py +73 -73
- package/md_cg/ccgc.py +1006 -948
- package/md_cg/census.py +132 -132
- package/md_cg/chain.py +315 -300
- package/md_cg/codeindex.py +531 -531
- package/md_cg/coldverify.py +292 -292
- package/md_cg/comment_gate.py +337 -337
- package/md_cg/cond_compose.py +190 -190
- package/md_cg/cond_facts.py +154 -154
- package/md_cg/cond_template.json +106 -106
- package/md_cg/condition_anchor.py +142 -142
- package/md_cg/conformance.py +726 -726
- package/md_cg/consistency.py +717 -717
- package/md_cg/consolidate.py +1537 -1439
- package/md_cg/corpus.py +110 -110
- package/md_cg/crosscheck.py +1098 -1097
- package/md_cg/crypto.py +3 -1
- package/md_cg/d_meta.py +310 -310
- package/md_cg/datapath.py +78 -18
- package/md_cg/docindex.py +473 -473
- package/md_cg/eval_common.py +575 -575
- package/md_cg/evidence.py +4 -2
- package/md_cg/evolution.py +477 -477
- package/md_cg/export.py +222 -220
- package/md_cg/forgetting.py +581 -581
- package/md_cg/fsutil.py +377 -329
- package/md_cg/hotcache.py +48 -7
- package/md_cg/hyperedge.py +251 -251
- package/md_cg/identity.py +390 -390
- package/md_cg/insight.py +500 -500
- package/md_cg/interop.py +338 -0
- package/md_cg/judgment_manifest.py +177 -0
- package/md_cg/lexicon/build_cedict_en_zh.py +329 -329
- package/md_cg/lexicon/build_standard_en.py +171 -171
- package/md_cg/lexicon/expand_en_zh.py +211 -211
- package/md_cg/lifecycle.py +272 -272
- package/md_cg/linkref.py +280 -280
- package/md_cg/links.py +140 -107
- package/md_cg/mcp_server.py +403 -55
- package/md_cg/md_whitebox.py +345 -345
- package/md_cg/mdcg.py +783 -233
- package/md_cg/mdcos.py +500 -70
- package/md_cg/metacognition.py +591 -591
- package/md_cg/migrate.py +119 -119
- package/md_cg/migrate_aeis.py +221 -221
- package/md_cg/migrate_roleplay.py +293 -293
- package/md_cg/migrate_wisdom_graph.py +360 -360
- package/md_cg/mreview/__init__.py +25 -25
- package/md_cg/mreview/__main__.py +110 -110
- package/md_cg/mreview/bundle.py +178 -178
- package/md_cg/mreview/candidates.py +262 -262
- package/md_cg/mreview/govern.py +694 -693
- package/md_cg/mreview/locate.py +939 -939
- package/md_cg/mreview/pipeline.py +728 -728
- package/md_cg/mreview/rules/duplication.json +21 -21
- package/md_cg/mreview/rules/field_coverage.json +54 -54
- package/md_cg/mreview/rules/source_license.json +21 -21
- package/md_cg/mreview/rules/template_flow.json +21 -21
- package/md_cg/mreview/ruleset.py +252 -252
- package/md_cg/nodefile.py +575 -575
- package/md_cg/pooling.py +484 -472
- package/md_cg/postings.py +300 -298
- package/md_cg/predict.py +1100 -1100
- package/md_cg/progressive.py +123 -123
- package/md_cg/protect.py +272 -272
- package/md_cg/protocol/md_cg_gate.proto +33 -33
- package/md_cg/protocol.py +372 -372
- package/md_cg/provenance.py +582 -582
- package/md_cg/reach.py +453 -453
- package/md_cg/readcache.py +143 -0
- package/md_cg/reconcile.py +228 -0
- package/md_cg/refindex.py +833 -833
- package/md_cg/refine.py +604 -604
- package/md_cg/review_cli.py +170 -0
- package/md_cg/roleviews.py +89 -89
- package/md_cg/routing.py +393 -365
- package/md_cg/run_tests.py +211 -0
- package/md_cg/scrub.py +13 -3
- package/md_cg/security.py +128 -18
- package/md_cg/self_state.py +1029 -1029
- package/md_cg/selfreport.py +152 -151
- package/md_cg/semantic/__init__.py +10 -10
- package/md_cg/semantic/canonical.py +122 -122
- package/md_cg/semantic/en_normalizer.py +364 -364
- package/md_cg/semantic/en_zh_map.json +28694 -0
- package/md_cg/semantic/export_en_zh_map.py +64 -0
- package/md_cg/semantic/unify.py +45 -0
- package/md_cg/semantic/zh_en_atoms.py +139 -139
- package/md_cg/signer.py +7 -4
- package/md_cg/sources.py +816 -582
- package/md_cg/statushdr.py +179 -179
- package/md_cg/stg.py +54 -37
- package/md_cg/subgraph.py +729 -729
- package/md_cg/sustain.py +35 -5
- package/md_cg/tasks.py +470 -470
- package/md_cg/test_access_hints.py +147 -0
- package/md_cg/test_action_derive.py +203 -203
- package/md_cg/test_audit_rotate.py +270 -270
- package/md_cg/test_autonomy.py +143 -143
- package/md_cg/test_bench_governance.py +102 -102
- package/md_cg/test_blindspot_tickets.py +166 -166
- package/md_cg/test_branch_discard_tombstone.py +136 -0
- package/md_cg/test_branches.py +13 -3
- package/md_cg/test_ccg_perturb.py +184 -184
- package/md_cg/test_ccgc.py +433 -433
- package/md_cg/test_census_prune.py +81 -81
- package/md_cg/test_chain_read_isolate.py +168 -0
- package/md_cg/test_cond_compose_anchors.py +76 -76
- package/md_cg/test_cond_match.py +165 -165
- package/md_cg/test_condition_anchor.py +81 -81
- package/md_cg/test_d_meta.py +412 -412
- package/md_cg/test_datapath_device_name.py +203 -0
- package/md_cg/test_datapath_root.py +199 -199
- package/md_cg/test_emit_negtail_cache.py +156 -0
- package/md_cg/test_en_pipeline.py +22 -2
- package/md_cg/test_gain_gate.py +212 -212
- package/md_cg/test_govern_directread.py +421 -0
- package/md_cg/test_health_scale.py +173 -173
- package/md_cg/test_hive_ingest.py +285 -0
- package/md_cg/test_hot_cold.py +215 -215
- package/md_cg/test_hyperedge.py +245 -245
- package/md_cg/test_i26_empty_first_write.py +116 -0
- package/md_cg/test_i27_e041_identity.py +128 -0
- package/md_cg/test_i28_hotcache_prodpath.py +122 -0
- package/md_cg/test_i32_hotcache_env_key.py +218 -0
- package/md_cg/test_identity_attribution.py +96 -15
- package/md_cg/test_index_durability.py +17 -3
- package/md_cg/test_interop.py +95 -0
- package/md_cg/test_interop_judgment.py +228 -0
- package/md_cg/test_issue39_utf8_stdio.py +273 -0
- package/md_cg/test_lifecycle.py +309 -309
- package/md_cg/test_linkref.py +306 -306
- package/md_cg/test_links_concurrent_write.py +188 -0
- package/md_cg/test_lock.py +43 -43
- package/md_cg/test_md_access_parity.py +255 -255
- package/md_cg/test_md_writepath.py +345 -345
- package/md_cg/test_mdstore_search_parity.py +160 -0
- package/md_cg/test_merge_upsert.py +168 -0
- package/md_cg/test_mr_m2.py +587 -587
- package/md_cg/test_mr_m3.py +710 -710
- package/md_cg/test_mr_m4.py +485 -485
- package/md_cg/test_n123_derive_expiry_chain.py +205 -0
- package/md_cg/test_n130_verify_falsified_protect.py +185 -0
- package/md_cg/test_n131_merge_gate.py +205 -0
- package/md_cg/test_p0.py +250 -250
- package/md_cg/test_p1.py +316 -316
- package/md_cg/test_p10_identity.py +173 -173
- package/md_cg/test_p11_consistency.py +233 -233
- package/md_cg/test_p12_metacognition.py +212 -212
- package/md_cg/test_p13_encryption.py +241 -241
- package/md_cg/test_p14_sustain.py +249 -249
- package/md_cg/test_p15_scrub.py +280 -280
- package/md_cg/test_p16_self_state.py +301 -301
- package/md_cg/test_p17_predict.py +354 -354
- package/md_cg/test_p18_whitebox.py +171 -171
- package/md_cg/test_p19_migrate_roleplay.py +149 -149
- package/md_cg/test_p1x_ref_root.py +160 -0
- package/md_cg/test_p20_evolution.py +315 -315
- package/md_cg/test_p21_tokens.py +293 -270
- package/md_cg/test_p22_theory.py +175 -175
- package/md_cg/test_p23_links.py +311 -311
- package/md_cg/test_p24_evidence.py +227 -227
- package/md_cg/test_p25_weights.py +156 -156
- package/md_cg/test_p26_refindex.py +416 -416
- package/md_cg/test_p27_docindex.py +16 -7
- package/md_cg/test_p28_refcheck.py +305 -305
- package/md_cg/test_p29_session_ingest_export.py +354 -333
- package/md_cg/test_p2_mcp.py +3 -0
- package/md_cg/test_p3.py +11 -2
- package/md_cg/test_p30_maintain.py +330 -330
- package/md_cg/test_p31_insight.py +534 -534
- package/md_cg/test_p32_backfill.py +7 -1
- package/md_cg/test_p33_ccg_wiring.py +293 -293
- package/md_cg/test_p34_crosscheck.py +331 -331
- package/md_cg/test_p35_conditioned_claim.py +252 -252
- package/md_cg/test_p36_kp_align.py +230 -230
- package/md_cg/test_p37_condition_space.py +248 -248
- package/md_cg/test_p38_concurrent_flush.py +102 -0
- package/md_cg/test_p38_contextualize.py +273 -273
- package/md_cg/test_p39_verify_flow.py +153 -0
- package/md_cg/test_p39_vision_evidence.py +369 -369
- package/md_cg/test_p40_refine_worklist.py +241 -241
- package/md_cg/test_p41_evolve_patrol.py +224 -224
- package/md_cg/test_p42_provenance.py +269 -269
- package/md_cg/test_p43_pooling.py +412 -398
- package/md_cg/test_p44_md_whitebox.py +231 -231
- package/md_cg/test_p45_session_identity.py +219 -219
- package/md_cg/test_p46_unit_scope.py +272 -272
- package/md_cg/test_p47_session_view.py +316 -0
- package/md_cg/test_p4_fuzzy.py +223 -223
- package/md_cg/test_p5_semantic.py +226 -226
- package/md_cg/test_p6_consolidate.py +440 -387
- package/md_cg/test_p7_goals_recent.py +202 -202
- package/md_cg/test_p8_subgraph_chain.py +200 -200
- package/md_cg/test_p9_forget_protect.py +231 -231
- package/md_cg/test_predict_beta.py +135 -135
- package/md_cg/test_preflight_failclosed.py +100 -100
- package/md_cg/test_progressive.py +146 -146
- package/md_cg/test_propose_tail_index.py +157 -0
- package/md_cg/test_protocol.py +243 -243
- package/md_cg/test_reach.py +378 -378
- package/md_cg/test_reach_keys.py +201 -201
- package/md_cg/test_read_clip.py +141 -141
- package/md_cg/test_read_scope_b27.py +277 -0
- package/md_cg/test_readcache_default_on.py +168 -0
- package/md_cg/test_readcache_precise_inval.py +270 -0
- package/md_cg/test_readcache_prodpath.py +203 -0
- package/md_cg/test_reconcile_v0.py +294 -0
- package/md_cg/test_retr_gates_prodpath.py +140 -0
- package/md_cg/test_retr_s1.py +344 -340
- package/md_cg/test_retr_s1b.py +276 -209
- package/md_cg/test_retr_s3.py +194 -194
- package/md_cg/test_retr_s4.py +163 -163
- package/md_cg/test_retr_s5.py +200 -200
- package/md_cg/test_retr_s6.py +157 -157
- package/md_cg/test_retr_s7.py +392 -384
- package/md_cg/test_retr_s8_time.py +369 -316
- package/md_cg/test_retr_s9_edges.py +286 -286
- package/md_cg/test_retr_s9_entity_ctx.py +9 -3
- package/md_cg/test_retr_score_once.py +208 -0
- package/md_cg/test_review_conformance.py +367 -367
- package/md_cg/test_review_onepass.py +170 -0
- package/md_cg/test_role_views.py +354 -354
- package/md_cg/test_rrf_graph_seed_cache.py +154 -0
- package/md_cg/test_security_audit.py +155 -0
- package/md_cg/test_security_audit_b26.py +161 -0
- package/md_cg/test_security_audit_v21.py +250 -0
- package/md_cg/test_sem_noise.py +242 -242
- package/md_cg/test_semantic_canonical.py +16 -2
- package/md_cg/test_session_isolation.py +168 -0
- package/md_cg/test_snapshot_autoclose.py +187 -0
- package/md_cg/test_subproc_encoding.py +192 -192
- package/md_cg/test_sustain_mutual.py +153 -153
- package/md_cg/test_tail_watermark_race.py +208 -0
- package/md_cg/test_tasks.py +409 -409
- package/md_cg/test_tenant_env_override_warn.py +139 -0
- package/md_cg/test_tenant_registry_corrupt_warn.py +151 -0
- package/md_cg/test_tool_face.py +189 -189
- package/md_cg/test_transfer.py +180 -180
- package/md_cg/test_trust.py +361 -361
- package/md_cg/test_twophase.py +286 -286
- package/md_cg/test_v14_fixes.py +38 -20
- package/md_cg/test_validity_filter.py +280 -280
- package/md_cg/test_verify_answer.py +138 -138
- package/md_cg/test_verify_dirty_reconcile.py +157 -0
- package/md_cg/test_wisdom_md_store.py +292 -292
- package/md_cg/test_writelimit.py +197 -197
- package/md_cg/test_writepipe.py +214 -214
- package/md_cg/theory.py +6 -3
- package/md_cg/tokens.py +85 -14
- package/md_cg/tool_face.py +260 -260
- package/md_cg/trust.py +986 -950
- package/md_cg/twophase.py +231 -231
- package/md_cg/units.py +668 -667
- package/md_cg/vision_evidence.py +667 -666
- package/md_cg/weights.py +624 -624
- package/md_cg/whitebox.py +527 -527
- package/md_cg/whitebox_kb/__init__.py +37 -37
- package/md_cg/whitebox_kb/aeis_core/__init__.py +42 -42
- package/md_cg/whitebox_kb/aeis_core/semantic.py +280 -280
- package/md_cg/whitebox_kb/aeis_core/textutil.py +13 -13
- package/md_cg/whitebox_kb/engine.py +310 -310
- package/md_cg/whitebox_kb/seed_knowledge//346/231/272/350/203/275/350/256/2723.4.md +5260 -5260
- package/md_cg/whitebox_kb/wisdom/browser_units.py +2631 -2631
- package/md_cg/whitebox_kb/wisdom/causal_discover.py +432 -432
- package/md_cg/whitebox_kb/wisdom/chat_engine.py +1506 -1506
- package/md_cg/whitebox_kb/wisdom/compiler_code_units.py +3033 -3033
- package/md_cg/whitebox_kb/wisdom/condition_algebra.py +112 -112
- package/md_cg/whitebox_kb/wisdom/condition_frame.py +315 -315
- package/md_cg/whitebox_kb/wisdom/condition_kb.py +108 -108
- package/md_cg/whitebox_kb/wisdom/conflict_map.json +4445 -4445
- package/md_cg/whitebox_kb/wisdom/core/lexer.py +512 -512
- package/md_cg/whitebox_kb/wisdom/core/name_checker.py +1023 -1023
- package/md_cg/whitebox_kb/wisdom/cspmn.py +258 -258
- package/md_cg/whitebox_kb/wisdom/csre.py +264 -264
- package/md_cg/whitebox_kb/wisdom/danmaku_audit.py +252 -252
- package/md_cg/whitebox_kb/wisdom/distilled_condition_units.json +6417 -6417
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902b.json +1950 -1950
- package/md_cg/whitebox_kb/wisdom/docs/WB-EVAL-20260902c.json +1296 -1296
- package/md_cg/whitebox_kb/wisdom/docs/whitebox_capability_graph_demo.json +59 -59
- package/md_cg/whitebox_kb/wisdom/graph_db_units.py +3089 -3089
- package/md_cg/whitebox_kb/wisdom/knowledge_points.py +318 -318
- package/md_cg/whitebox_kb/wisdom/md_access.py +470 -470
- package/md_cg/whitebox_kb/wisdom/md_store.py +276 -251
- package/md_cg/whitebox_kb/wisdom/migrate_wisdom.py +476 -476
- package/md_cg/whitebox_kb/wisdom/multilang_ir.py +128 -124
- package/md_cg/whitebox_kb/wisdom/navigate.py +248 -248
- package/md_cg/whitebox_kb/wisdom/neural_retrieve.py +224 -224
- package/md_cg/whitebox_kb/wisdom/os_units.py +2735 -2735
- package/md_cg/whitebox_kb/wisdom/pattern_separation.py +376 -376
- package/md_cg/whitebox_kb/wisdom/prereq_map.json +364 -364
- package/md_cg/whitebox_kb/wisdom/python_code_units.py +2766 -2766
- package/md_cg/whitebox_kb/wisdom/role_solidified.json +7 -7
- package/md_cg/whitebox_kb/wisdom/route_memory.py +244 -244
- package/md_cg/whitebox_kb/wisdom/scene_reconstruction.py +148 -148
- package/md_cg/whitebox_kb/wisdom/snr_report.json +40 -40
- package/md_cg/whitebox_kb/wisdom/test_code_compose_domains.py +7541 -7541
- package/md_cg/whitebox_kb/wisdom/test_compiler_self_bootstrap.py +354 -354
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_assembly.py +158 -158
- package/md_cg/whitebox_kb/wisdom/test_ecosystem_demos.py +193 -193
- package/md_cg/whitebox_kb/wisdom/test_graph_db.py +292 -292
- package/md_cg/whitebox_kb/wisdom/test_python_self_bootstrap.py +160 -160
- package/md_cg/whitebox_kb/wisdom/trigger_words_index.json +4366 -4366
- package/md_cg/whitebox_kb/wisdom/verifier.py +1297 -1297
- package/md_cg/writelimit.py +356 -356
- package/md_cg/writepipe.py +20 -8
- package/package.json +101 -96
- package/skills/plugin.json +54 -54
- package/skills/skills/designer-perspective/SKILL.md +158 -158
- package/skills/skills/designer-perspective/references/01-observation-position.md +66 -66
- package/skills/skills/designer-perspective/references/02-structure-recognition.md +62 -62
- package/skills/skills/designer-perspective/references/03-direction-judgment.md +55 -55
- package/skills/skills/designer-perspective/references/04-qualification-verdict.md +72 -72
- package/skills/skills/designer-perspective/references/05-condition-attribution.md +74 -74
- package/skills/skills/designer-perspective/scripts/designer.py +545 -545
- package/skills/skills/designer-perspective/tests/cases.jsonl +17 -17
- package/skills/skills/designer-perspective/tests/selftest.py +61 -61
- package/skills/skills/lingshu-browser/SKILL.md +60 -60
- package/skills/skills/lingshu-compiler/SKILL.md +56 -56
- package/skills/skills/lingshu-compiler/units/analyze-type-infer/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/check-name-real/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-assign/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-expr-tree/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-full-pipeline/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-func-def/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-if-then/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-logic-expr/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-recursive/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-scope/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-type-check/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compile-while/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0010c4bf/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0355bffb/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0361708a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-054a0414/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05a1691a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-05eeed1e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0622a1f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-08b54217/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0a62b70c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ab24d00/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e093688/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0e82b966/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0ee9b9b9/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-0f3787e6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1028685f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-11897630/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-16661b9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-1f722303/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-25be1262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2a76ba07/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2dbea54a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2df52f16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2ec2c9d2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-2f8c8f39/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-38378ac7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39457d2e/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-39fb5926/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-47f4fbfa/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4a8cd1f1/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4b230b6b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4cbbda95/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-4d5a68ff/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-56dc9bdd/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-57e76ebe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-61ff016b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-63eae588/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-64c4224b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-66377955/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-674ab4f6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6af76fd6/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6d979db2/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6de326c0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-6f1c0eea/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-724d6c9b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7690177f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7b229a7d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-7f471b3a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-815cad08/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-83c61634/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8c798c81/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-8dd747ac/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-90324d0a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94b8d72d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-94f12231/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-95937c16/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98a5625b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98b4c42f/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-98e3894a/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9bdfe4b8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9d9b4e83/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-9f7be5ad/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a6daf076/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a7995a0c/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-a8399248/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-aabbd099/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-afe169d8/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b0678bda/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b09bd196/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b1396e23/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-b9b31ce0/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-c10264a7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cb1e8e4b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ccafd438/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cda9c262/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ce648068/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-cf5776a4/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-d974e5d3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-e3979fd3/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-eb1cf2b5/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-ecb30d5b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f8c8b24b/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-f99fedbe/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fa8ff5f7/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/compiler-fe1b058d/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-chinese-program/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-dao-de-jing/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/lex-nine-chapters/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-arithmetic/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-array-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-closure-create/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-compare/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-jump/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-cond-space/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-exception/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-func-call/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-loop-run/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-profiling/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-refcount/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-run-loop/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-short-circuit/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-guard/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-stack-ops/SKILL.md +45 -45
- package/skills/skills/lingshu-compiler/units/vm-trust-accum/SKILL.md +45 -45
- package/skills/skills/lingshu-graph/SKILL.md +63 -63
- package/skills/skills/lingshu-net/SKILL.md +48 -48
- package/skills/skills/lingshu-os/SKILL.md +64 -64
- package/skills/skills/lingshu-pylang/SKILL.md +71 -71
- package/src/bridge.ts +33 -0
- package/src/hooks.ts +38 -2
- package/src/index.ts +526 -518
- package/src/lib/datapath.ts +326 -326
- package/src/lib/mdcg_client.ts +413 -413
- package/src/lib/mutual.ts +428 -428
- package/src/lib/prompt_safety.ts +62 -62
- package/src/lib/python_path.ts +71 -71
- package/src/lib/roleplay_web.ts +116 -29
- package/src/lib/token_store.ts +13 -3
- package/src/tools.ts +212 -212
- package/zcode/AGENTS.md +11 -3
- package/zcode/README.md +41 -41
- /package/docs/{mdcg → hive}//344/270/273/344/273/243/347/220/206/345/255/220/344/273/243/347/220/206/350/256/260/345/277/206/346/236/266/346/236/204/350/256/276/350/256/241.md" +0 -0
package/md_cg/units.py
CHANGED
|
@@ -1,668 +1,669 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
"""units.py · 复核单元接线层:蜂巢优先 → 提示配置 → harness 端子代理降级。
|
|
3
|
-
|
|
4
|
-
定位(与 audit.py 同一条架构约束):**能力不在认知图内**。本模块不做智能判定,
|
|
5
|
-
只做三件事:选通道(probe/plan)→ 派发请求(submit/wait/run)→ 记账(_units.jsonl)。
|
|
6
|
-
|
|
7
|
-
使用者裁定(2026-09-16,第 17 条精神):编译器(ccgc)的复核**优先使用蜂巢的
|
|
8
|
-
反思单元 / 验证单元**(reflect / verify,与 crosscheck.REFLECT_UNIT/VERIFY_UNIT 同值,
|
|
9
|
-
不新造角色名);蜂巢不可用 → **提示使用者配置**(给出可照做的构建/启动/环境变量命令);
|
|
10
|
-
或经显式 allow_degrade=True 降级到 **harness 端子代理**(宿主 agent 派发,裁决经
|
|
11
|
-
crosscheck 同款 verdicts 通道回填)。理由:使用者的复核是昂贵的——重活交给可并行的
|
|
12
|
-
外部单元,agent 本体只做编排与记账。
|
|
13
|
-
|
|
14
|
-
蜂巢契约(真源 hive/README.md + hive/hive_mcp/mcp_server.py;**复制契约不 import**,
|
|
15
|
-
保持 md_cg 对 hive 零依赖,与 ccgc「同款语义就地实现防 import 环」惯例一致):
|
|
16
|
-
jobs 目录 = $HIVE_JOBS_DIR | <repo>/hive/jobs
|
|
17
|
-
serve 判活 = **三层**:jobs/_serve.json 的 ts(毫秒)距今 < FRESH_S(15s)
|
|
18
|
-
∧ pid 存活 ∧ 该 pid 是本程序
|
|
19
|
-
(同 hive/serve_start.serve_alive;四路口径由
|
|
20
|
-
hive/test_serve_entry.py 机械守卫)
|
|
21
|
-
job 目录 = jobs/<job_id>/{spec.json,status.json,result.json,kill}
|
|
22
|
-
job_id = h<java_ms>_<uuid6> (同 _submit)
|
|
23
|
-
result.json = {"ok":true,"content":...} | {"ok":false,"error":...}
|
|
24
|
-
终态 = done | error | timeout | killed
|
|
25
|
-
拉起 serve = <repo>/hive/target/release/hive serve --jobs <jobs>(detached)
|
|
26
|
-
|
|
27
|
-
边界(诚实声明,不猜测):
|
|
28
|
-
· 本模块**不产生裁决**,只搬运;裁决由外部单元负责。
|
|
29
|
-
· 契约漂移:hive 侧协议若变更,本模块以「无 result / 超时」如实失败,不假装成功。
|
|
30
|
-
· 默认**不自动拉起 serve**(使用者裁定:不可用即提示配置);autostart=True 才拉起。
|
|
31
|
-
"""
|
|
32
|
-
from __future__ import annotations
|
|
33
|
-
|
|
34
|
-
import json
|
|
35
|
-
import os
|
|
36
|
-
import re
|
|
37
|
-
import subprocess
|
|
38
|
-
import time
|
|
39
|
-
import uuid
|
|
40
|
-
|
|
41
|
-
HIVE, SUBAGENT, CONFIGURE = "hive", "subagent", "configure"
|
|
42
|
-
STATES = (HIVE, SUBAGENT, CONFIGURE)
|
|
43
|
-
|
|
44
|
-
REFLECT, VERIFY = "reflect", "verify" # 同 crosscheck.REFLECT_UNIT/VERIFY_UNIT
|
|
45
|
-
ROLES = (REFLECT, VERIFY)
|
|
46
|
-
|
|
47
|
-
SERVE_FILE, SPEC_FILE = "_serve.json", "spec.json"
|
|
48
|
-
STATUS_FILE, RESULT_FILE, KILL_FILE = "status.json", "result.json", "kill"
|
|
49
|
-
LOG_NAME = "_units.jsonl"
|
|
50
|
-
TERMINAL_STATES = ("done", "error", "timeout", "killed")
|
|
51
|
-
#: serve 心跳新鲜窗口(秒)。**须与 hive/serve_start.FRESH_S 同值**——本模块
|
|
52
|
-
#: 只持有「判活的第 4 处实现」(复制契约不 import hive),阈值/判据结构若与
|
|
53
|
-
#: 权威漂移,会在通道选择面复现 v13 的「假存活」病类(v14 缺陷 E:
|
|
54
|
-
#: 旧值 5.0 vs 权威 15,serve 崩溃后 ≤5s 窗口内判「存活」→ 选 hive 通道 →
|
|
55
|
-
#: 提交的 job 永远无人处理)。守卫:hive/test_serve_entry.py。
|
|
56
|
-
FRESH_S, DEFAULT_TIMEOUT_S, DEFAULT_POLL_S = 15.0, 120, 1.0
|
|
57
|
-
#: 复核委派的 completion 预算。**必须对齐统一默认(文档:最大输出 200000)**——
|
|
58
|
-
#: 该模型 reasoning 与正文**共享 completion 预算**,小预算会把正文吃光并静默返回空正文:
|
|
59
|
-
#: 实测 2048 → reasoning 2048 / content 空;16384 → 时好时坏;200000 → 正常出裁决。
|
|
60
|
-
DEFAULT_MAX_TOKENS = 200000
|
|
61
|
-
|
|
62
|
-
ENV_JOBS_DIR, ENV_EXE = "HIVE_JOBS_DIR", "HIVE_EXE"
|
|
63
|
-
ENV_MODEL, ENV_API_KEY = "MDCG_UNIT_MODEL", "HIVE_API_KEY"
|
|
64
|
-
|
|
65
|
-
ACCEPT, REJECT, DEFER, BLINDSPOT = "ACCEPT", "REJECT", "DEFER", "BLINDSPOT"
|
|
66
|
-
_VERDICT_MAP = {
|
|
67
|
-
"accept": ACCEPT, "accepted": ACCEPT, "keep": ACCEPT, "pass": ACCEPT,
|
|
68
|
-
"ok": ACCEPT, "approve": ACCEPT,
|
|
69
|
-
"drop": REJECT, "reject": REJECT, "rejected": REJECT, "deny": REJECT, "fail": REJECT,
|
|
70
|
-
"defer": DEFER, "deferred": DEFER, "unsure": DEFER, "unclear": DEFER, "skip": DEFER,
|
|
71
|
-
"blindspot": BLINDSPOT, "blind": BLINDSPOT,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
# 生效条件:无入参,恒返回模块 `__file__` 绝对路径上溯两级的目录(md_cg 的上一级),与 cwd 无关。
|
|
76
|
-
def repo_root() -> str:
|
|
77
|
-
"""仓库根(md_cg 的上一级);不用 cwd——cwd 由宿主决定,不可作判据。"""
|
|
78
|
-
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
# 生效条件:explicit 为真值时 d=explicit;explicit 为空串等假值而 ENV_JOBS_DIR 有真值时 d=该环境变量;两者皆假值时 d=repo_root()/hive/jobs;最终返回 os.path.abspath(d)。
|
|
82
|
-
def jobs_dir(explicit: str = "") -> str:
|
|
83
|
-
d = explicit or os.environ.get(ENV_JOBS_DIR) or os.path.join(repo_root(), "hive", "jobs")
|
|
84
|
-
return os.path.abspath(d)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# 生效条件:ENV_EXE 有真值时原样返回该值;ENV_EXE 缺失或为空串时返回 repo_root()/hive/target/release/ 下按 os.name=="nt" 取 hive.exe、否则取 hive 的拼接路径。
|
|
88
|
-
def exe_path() -> str:
|
|
89
|
-
exe = os.environ.get(ENV_EXE)
|
|
90
|
-
if exe:
|
|
91
|
-
return exe
|
|
92
|
-
return os.path.join(repo_root(), "hive", "target", "release",
|
|
93
|
-
"hive.exe" if os.name == "nt" else "hive")
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
# 生效条件:explicit 为真值时取 explicit,否则取 ENV_MODEL,两者皆假值时按空串,返回该结果 strip() 后的字符串(可为空串)。
|
|
97
|
-
def model_name(explicit: str = "") -> str:
|
|
98
|
-
"""复核模型(LLM 委托型执行器的 spec.model 必填)。"""
|
|
99
|
-
return (explicit or os.environ.get(ENV_MODEL) or "").strip()
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# 生效条件:pid 为 int 且大于 0 时(否则 False),os.name 为 "nt" 时返回 _tasklist_row(pid) 是否非 None,非 "nt" 时 os.kill(pid, 0) 不抛 OSError 返回 True、抛 OSError 返回 False。
|
|
103
|
-
def pid_alive(pid) -> bool:
|
|
104
|
-
"""该 pid **号**是否存在(Windows tasklist 精确列比对 / unix `kill -0`)。
|
|
105
|
-
|
|
106
|
-
只回答「这个号有没有进程」——**不足以判定「serve 还在跑」**(见
|
|
107
|
-
`pid_is_self_program`)。实现与 hive/serve_start.pid_alive 同口径。
|
|
108
|
-
"""
|
|
109
|
-
if not isinstance(pid, int) or pid <= 0:
|
|
110
|
-
return False
|
|
111
|
-
if os.name == "nt":
|
|
112
|
-
return _tasklist_row(pid) is not None
|
|
113
|
-
try:
|
|
114
|
-
os.kill(pid, 0)
|
|
115
|
-
return True
|
|
116
|
-
except OSError:
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
# 生效条件:对传入 pid 执行 tasklist /FO CSV 后,在其 stdout 中遇到的第一个按 '","' 切分、列数≥2 且第 2 列 strip 再 strip('"') 后等于 str(pid) 的行即返回 [映像名, pid 字符串],无此行或 subprocess.run 抛 OSError 时返回 None。
|
|
121
|
-
def _tasklist_row(pid):
|
|
122
|
-
"""Windows:查该 pid 的 tasklist 行 → [映像名, pid 字符串];查不到返回 None。
|
|
123
|
-
|
|
124
|
-
按列精确比对,**不用子串包含**——子串会让 pid=441 被 4410 命中(假存活)。
|
|
125
|
-
"""
|
|
126
|
-
try:
|
|
127
|
-
# 显式 utf-8 + replace:只消费 ASCII 的 pid 列,但**不依赖 locale**——
|
|
128
|
-
# locale 口径与「后代写 UTF-8」不一致时读线程会崩(见 test_subproc_encoding.py)。
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
"
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
%
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
"
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
"
|
|
216
|
-
"
|
|
217
|
-
"
|
|
218
|
-
"
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
if
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
"
|
|
241
|
-
"
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
"
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
"
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
rec
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
"
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
"
|
|
322
|
-
"
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
out["
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
out["
|
|
364
|
-
out["
|
|
365
|
-
out["
|
|
366
|
-
out["
|
|
367
|
-
|
|
368
|
-
#
|
|
369
|
-
#
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
out["
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
res
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
corr =
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
- state=
|
|
576
|
-
- state=
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
"
|
|
583
|
-
"
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
"
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
"
|
|
609
|
-
|
|
610
|
-
out["
|
|
611
|
-
out["
|
|
612
|
-
out["
|
|
613
|
-
out["
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
"
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
"
|
|
664
|
-
"
|
|
665
|
-
"
|
|
666
|
-
"
|
|
667
|
-
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""units.py · 复核单元接线层:蜂巢优先 → 提示配置 → harness 端子代理降级。
|
|
3
|
+
|
|
4
|
+
定位(与 audit.py 同一条架构约束):**能力不在认知图内**。本模块不做智能判定,
|
|
5
|
+
只做三件事:选通道(probe/plan)→ 派发请求(submit/wait/run)→ 记账(_units.jsonl)。
|
|
6
|
+
|
|
7
|
+
使用者裁定(2026-09-16,第 17 条精神):编译器(ccgc)的复核**优先使用蜂巢的
|
|
8
|
+
反思单元 / 验证单元**(reflect / verify,与 crosscheck.REFLECT_UNIT/VERIFY_UNIT 同值,
|
|
9
|
+
不新造角色名);蜂巢不可用 → **提示使用者配置**(给出可照做的构建/启动/环境变量命令);
|
|
10
|
+
或经显式 allow_degrade=True 降级到 **harness 端子代理**(宿主 agent 派发,裁决经
|
|
11
|
+
crosscheck 同款 verdicts 通道回填)。理由:使用者的复核是昂贵的——重活交给可并行的
|
|
12
|
+
外部单元,agent 本体只做编排与记账。
|
|
13
|
+
|
|
14
|
+
蜂巢契约(真源 hive/README.md + hive/hive_mcp/mcp_server.py;**复制契约不 import**,
|
|
15
|
+
保持 md_cg 对 hive 零依赖,与 ccgc「同款语义就地实现防 import 环」惯例一致):
|
|
16
|
+
jobs 目录 = $HIVE_JOBS_DIR | <repo>/hive/jobs
|
|
17
|
+
serve 判活 = **三层**:jobs/_serve.json 的 ts(毫秒)距今 < FRESH_S(15s)
|
|
18
|
+
∧ pid 存活 ∧ 该 pid 是本程序
|
|
19
|
+
(同 hive/serve_start.serve_alive;四路口径由
|
|
20
|
+
hive/test_serve_entry.py 机械守卫)
|
|
21
|
+
job 目录 = jobs/<job_id>/{spec.json,status.json,result.json,kill}
|
|
22
|
+
job_id = h<java_ms>_<uuid6> (同 _submit)
|
|
23
|
+
result.json = {"ok":true,"content":...} | {"ok":false,"error":...}
|
|
24
|
+
终态 = done | error | timeout | killed
|
|
25
|
+
拉起 serve = <repo>/hive/target/release/hive serve --jobs <jobs>(detached)
|
|
26
|
+
|
|
27
|
+
边界(诚实声明,不猜测):
|
|
28
|
+
· 本模块**不产生裁决**,只搬运;裁决由外部单元负责。
|
|
29
|
+
· 契约漂移:hive 侧协议若变更,本模块以「无 result / 超时」如实失败,不假装成功。
|
|
30
|
+
· 默认**不自动拉起 serve**(使用者裁定:不可用即提示配置);autostart=True 才拉起。
|
|
31
|
+
"""
|
|
32
|
+
from __future__ import annotations
|
|
33
|
+
|
|
34
|
+
import json
|
|
35
|
+
import os
|
|
36
|
+
import re
|
|
37
|
+
import subprocess
|
|
38
|
+
import time
|
|
39
|
+
import uuid
|
|
40
|
+
|
|
41
|
+
HIVE, SUBAGENT, CONFIGURE = "hive", "subagent", "configure"
|
|
42
|
+
STATES = (HIVE, SUBAGENT, CONFIGURE)
|
|
43
|
+
|
|
44
|
+
REFLECT, VERIFY = "reflect", "verify" # 同 crosscheck.REFLECT_UNIT/VERIFY_UNIT
|
|
45
|
+
ROLES = (REFLECT, VERIFY)
|
|
46
|
+
|
|
47
|
+
SERVE_FILE, SPEC_FILE = "_serve.json", "spec.json"
|
|
48
|
+
STATUS_FILE, RESULT_FILE, KILL_FILE = "status.json", "result.json", "kill"
|
|
49
|
+
LOG_NAME = "_units.jsonl"
|
|
50
|
+
TERMINAL_STATES = ("done", "error", "timeout", "killed")
|
|
51
|
+
#: serve 心跳新鲜窗口(秒)。**须与 hive/serve_start.FRESH_S 同值**——本模块
|
|
52
|
+
#: 只持有「判活的第 4 处实现」(复制契约不 import hive),阈值/判据结构若与
|
|
53
|
+
#: 权威漂移,会在通道选择面复现 v13 的「假存活」病类(v14 缺陷 E:
|
|
54
|
+
#: 旧值 5.0 vs 权威 15,serve 崩溃后 ≤5s 窗口内判「存活」→ 选 hive 通道 →
|
|
55
|
+
#: 提交的 job 永远无人处理)。守卫:hive/test_serve_entry.py。
|
|
56
|
+
FRESH_S, DEFAULT_TIMEOUT_S, DEFAULT_POLL_S = 15.0, 120, 1.0
|
|
57
|
+
#: 复核委派的 completion 预算。**必须对齐统一默认(文档:最大输出 200000)**——
|
|
58
|
+
#: 该模型 reasoning 与正文**共享 completion 预算**,小预算会把正文吃光并静默返回空正文:
|
|
59
|
+
#: 实测 2048 → reasoning 2048 / content 空;16384 → 时好时坏;200000 → 正常出裁决。
|
|
60
|
+
DEFAULT_MAX_TOKENS = 200000
|
|
61
|
+
|
|
62
|
+
ENV_JOBS_DIR, ENV_EXE = "HIVE_JOBS_DIR", "HIVE_EXE"
|
|
63
|
+
ENV_MODEL, ENV_API_KEY = "MDCG_UNIT_MODEL", "HIVE_API_KEY"
|
|
64
|
+
|
|
65
|
+
ACCEPT, REJECT, DEFER, BLINDSPOT = "ACCEPT", "REJECT", "DEFER", "BLINDSPOT"
|
|
66
|
+
_VERDICT_MAP = {
|
|
67
|
+
"accept": ACCEPT, "accepted": ACCEPT, "keep": ACCEPT, "pass": ACCEPT,
|
|
68
|
+
"ok": ACCEPT, "approve": ACCEPT,
|
|
69
|
+
"drop": REJECT, "reject": REJECT, "rejected": REJECT, "deny": REJECT, "fail": REJECT,
|
|
70
|
+
"defer": DEFER, "deferred": DEFER, "unsure": DEFER, "unclear": DEFER, "skip": DEFER,
|
|
71
|
+
"blindspot": BLINDSPOT, "blind": BLINDSPOT,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
# 生效条件:无入参,恒返回模块 `__file__` 绝对路径上溯两级的目录(md_cg 的上一级),与 cwd 无关。
|
|
76
|
+
def repo_root() -> str:
|
|
77
|
+
"""仓库根(md_cg 的上一级);不用 cwd——cwd 由宿主决定,不可作判据。"""
|
|
78
|
+
return os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
# 生效条件:explicit 为真值时 d=explicit;explicit 为空串等假值而 ENV_JOBS_DIR 有真值时 d=该环境变量;两者皆假值时 d=repo_root()/hive/jobs;最终返回 os.path.abspath(d)。
|
|
82
|
+
def jobs_dir(explicit: str = "") -> str:
|
|
83
|
+
d = explicit or os.environ.get(ENV_JOBS_DIR) or os.path.join(repo_root(), "hive", "jobs")
|
|
84
|
+
return os.path.abspath(d)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
# 生效条件:ENV_EXE 有真值时原样返回该值;ENV_EXE 缺失或为空串时返回 repo_root()/hive/target/release/ 下按 os.name=="nt" 取 hive.exe、否则取 hive 的拼接路径。
|
|
88
|
+
def exe_path() -> str:
|
|
89
|
+
exe = os.environ.get(ENV_EXE)
|
|
90
|
+
if exe:
|
|
91
|
+
return exe
|
|
92
|
+
return os.path.join(repo_root(), "hive", "target", "release",
|
|
93
|
+
"hive.exe" if os.name == "nt" else "hive")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
# 生效条件:explicit 为真值时取 explicit,否则取 ENV_MODEL,两者皆假值时按空串,返回该结果 strip() 后的字符串(可为空串)。
|
|
97
|
+
def model_name(explicit: str = "") -> str:
|
|
98
|
+
"""复核模型(LLM 委托型执行器的 spec.model 必填)。"""
|
|
99
|
+
return (explicit or os.environ.get(ENV_MODEL) or "").strip()
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
# 生效条件:pid 为 int 且大于 0 时(否则 False),os.name 为 "nt" 时返回 _tasklist_row(pid) 是否非 None,非 "nt" 时 os.kill(pid, 0) 不抛 OSError 返回 True、抛 OSError 返回 False。
|
|
103
|
+
def pid_alive(pid) -> bool:
|
|
104
|
+
"""该 pid **号**是否存在(Windows tasklist 精确列比对 / unix `kill -0`)。
|
|
105
|
+
|
|
106
|
+
只回答「这个号有没有进程」——**不足以判定「serve 还在跑」**(见
|
|
107
|
+
`pid_is_self_program`)。实现与 hive/serve_start.pid_alive 同口径。
|
|
108
|
+
"""
|
|
109
|
+
if not isinstance(pid, int) or pid <= 0:
|
|
110
|
+
return False
|
|
111
|
+
if os.name == "nt":
|
|
112
|
+
return _tasklist_row(pid) is not None
|
|
113
|
+
try:
|
|
114
|
+
os.kill(pid, 0)
|
|
115
|
+
return True
|
|
116
|
+
except OSError:
|
|
117
|
+
return False
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# 生效条件:对传入 pid 执行 tasklist /FO CSV 后,在其 stdout 中遇到的第一个按 '","' 切分、列数≥2 且第 2 列 strip 再 strip('"') 后等于 str(pid) 的行即返回 [映像名, pid 字符串],无此行或 subprocess.run 抛 OSError 时返回 None。
|
|
121
|
+
def _tasklist_row(pid):
|
|
122
|
+
"""Windows:查该 pid 的 tasklist 行 → [映像名, pid 字符串];查不到返回 None。
|
|
123
|
+
|
|
124
|
+
按列精确比对,**不用子串包含**——子串会让 pid=441 被 4410 命中(假存活)。
|
|
125
|
+
"""
|
|
126
|
+
try:
|
|
127
|
+
# 显式 utf-8 + replace:只消费 ASCII 的 pid 列,但**不依赖 locale**——
|
|
128
|
+
# locale 口径与「后代写 UTF-8」不一致时读线程会崩(见 test_subproc_encoding.py)。
|
|
129
|
+
# P2-16(批次 30):timeout=10——tasklist 挂起曾永久阻塞判活路径。
|
|
130
|
+
r = subprocess.run(["tasklist", "/FI", f"PID eq {pid}", "/NH", "/FO", "CSV"],
|
|
131
|
+
capture_output=True, text=True,
|
|
132
|
+
encoding="utf-8", errors="replace", timeout=10)
|
|
133
|
+
except (OSError, subprocess.SubprocessError):
|
|
134
|
+
return None
|
|
135
|
+
for line in (r.stdout or "").splitlines():
|
|
136
|
+
cols = line.split('","')
|
|
137
|
+
if len(cols) >= 2 and cols[1].strip().strip('"') == str(pid):
|
|
138
|
+
return [cols[0].strip().strip('"'), cols[1].strip().strip('"')]
|
|
139
|
+
return None
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
# 生效条件:exe_path() 的 basename 小写非空且 pid 为 int 大于 0 时(否则 False),"nt" 下要求 _tasklist_row(pid) 非空且映像名小写等于该 basename,非 "nt" 下要求 /proc/<pid>/cmdline 首个 b"\x00" 前 token 的 basename 小写等于它(读取抛 OSError 则 False)。
|
|
143
|
+
def pid_is_self_program(pid) -> bool:
|
|
144
|
+
"""该 pid 是否**就是本程序**(同映像名)——pid 号会被无关进程复用。
|
|
145
|
+
|
|
146
|
+
与 hive/serve_start.pid_is_self_program 同口径(复制契约)。零依赖边界:
|
|
147
|
+
拿不到映像名返回 False(宁可放行启动,也不误报「已有 serve 在跑」)。
|
|
148
|
+
"""
|
|
149
|
+
want = os.path.basename(exe_path()).lower()
|
|
150
|
+
if not want or not isinstance(pid, int) or pid <= 0:
|
|
151
|
+
return False
|
|
152
|
+
if os.name == "nt":
|
|
153
|
+
row = _tasklist_row(pid)
|
|
154
|
+
return bool(row) and row[0].lower() == want
|
|
155
|
+
try:
|
|
156
|
+
with open(f"/proc/{pid}/cmdline", "rb") as f:
|
|
157
|
+
first = f.read().split(b"\x00")[0]
|
|
158
|
+
except OSError:
|
|
159
|
+
return False
|
|
160
|
+
return os.path.basename(first.decode("utf-8", "replace")).lower() == want
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
# 生效条件:以 jobs_dir(jobs) 下的 SERVE_FILE 为心跳路径——该路径不被 isfile 命中时返回 exists/alive 均 False 的未启动 reason;命中但 open/json.load 抛 OSError 或 ValueError 时返回不可读 reason;解析成功后按**三层判据**(age < fresh_s ∧ pid_alive(pid) ∧ pid_is_self_program(pid))定 alive,回填 age_s/pid/raw 与逐层明细及失败原因。
|
|
164
|
+
def serve_state(jobs: str = "", fresh_s: float = FRESH_S) -> dict:
|
|
165
|
+
"""serve 判活:**三层**(心跳新鲜 ∧ pid 存活 ∧ 该 pid 是本程序)。
|
|
166
|
+
|
|
167
|
+
与 `hive/serve_start.serve_alive` 同口径(同值 FRESH_S=15s、同三层判据)。
|
|
168
|
+
v14 缺陷 E:旧实现只判 ts 新鲜度且阈值 5s——双漂移,serve 崩溃后
|
|
169
|
+
≤5s 内判「存活」会让 `probe()` 选 hive 通道(提交的 job 永远无人处理),
|
|
170
|
+
这正是 v13「假存活」病类从守卫面搬到了**通道选择面**。
|
|
171
|
+
"""
|
|
172
|
+
jd = jobs_dir(jobs)
|
|
173
|
+
p = os.path.join(jd, SERVE_FILE)
|
|
174
|
+
out = {"jobs_dir": jd, "heartbeat": p, "exists": os.path.isfile(p),
|
|
175
|
+
"alive": False, "age_s": None, "pid": None, "reason": ""}
|
|
176
|
+
if not out["exists"]:
|
|
177
|
+
out["reason"] = "未见 _serve.json 心跳(serve 未启动或 jobs 目录不对)"
|
|
178
|
+
return out
|
|
179
|
+
try:
|
|
180
|
+
with open(p, encoding="utf-8") as f:
|
|
181
|
+
hb = json.load(f)
|
|
182
|
+
except (OSError, ValueError) as exc:
|
|
183
|
+
out["reason"] = "心跳不可读:%s: %s" % (type(exc).__name__, exc)
|
|
184
|
+
return out
|
|
185
|
+
age = time.time() - ((hb.get("ts") or 0) / 1000.0)
|
|
186
|
+
pid = hb.get("pid")
|
|
187
|
+
fresh_ok = age < float(fresh_s)
|
|
188
|
+
pid_ok = pid_alive(pid)
|
|
189
|
+
ident_ok = pid_is_self_program(pid)
|
|
190
|
+
out.update({"age_s": round(age, 3), "pid": pid, "raw": hb,
|
|
191
|
+
"fresh": bool(fresh_ok), "pid_alive": bool(pid_ok),
|
|
192
|
+
"pid_is_self_program": bool(ident_ok)})
|
|
193
|
+
out["alive"] = bool(fresh_ok and pid_ok and ident_ok)
|
|
194
|
+
if out["alive"]:
|
|
195
|
+
out["reason"] = ""
|
|
196
|
+
elif not fresh_ok:
|
|
197
|
+
out["reason"] = "心跳过期 %.1fs(阈值 %ss)——serve 可能已退出" % (age, fresh_s)
|
|
198
|
+
elif not pid_ok:
|
|
199
|
+
out["reason"] = "心跳新鲜但 pid=%s 已不存在——serve 已退出" % (pid,)
|
|
200
|
+
else:
|
|
201
|
+
out["reason"] = ("心跳新鲜且 pid=%s 存活,但该 pid 不属于本程序"
|
|
202
|
+
"(非 %s)——pid 号被无关进程复用"
|
|
203
|
+
% (pid, os.path.basename(exe_path())))
|
|
204
|
+
return out
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
# 生效条件:jobs 仅经 jobs_dir(jobs) 用于填充指引里的 jobs 路径;reason 为假值时文案首行取“serve 未存活”,否则取 reason 原文;返回模板固定嵌入 exe_path() 的目录与路径、ENV_API_KEY、ENV_MODEL、jd、jd 下的 SERVE_FILE 与 int(FRESH_S)。
|
|
208
|
+
def setup_hint(jobs: str = "", reason: str = "") -> str:
|
|
209
|
+
"""不可用时给使用者看的**配置指引**(含降级指引)——提示即责任,须可照着做。"""
|
|
210
|
+
jd = jobs_dir(jobs)
|
|
211
|
+
return ("蜂巢不可用:%s\n"
|
|
212
|
+
" [A 配置蜂巢(推荐,第 17 条)]\n"
|
|
213
|
+
" 1) cd %s && cargo build --release\n"
|
|
214
|
+
" 2) set %s=<LLM密钥>\n 3) set %s=<复核模型名>\n"
|
|
215
|
+
" 4) 启动:%s serve --jobs \"%s\"(或 hive_spawn 自动拉起)\n"
|
|
216
|
+
" 判活判据:%s 的 ts 距今 < %ss\n"
|
|
217
|
+
" [B 降级 harness 端子代理]\n"
|
|
218
|
+
" 重发本请求并带 allow_degrade=true:本模块返回复核请求包(prompt),\n"
|
|
219
|
+
" 由宿主子代理执行后经 verdicts 回填裁决。"
|
|
220
|
+
% (reason or "serve 未存活", os.path.dirname(exe_path()), ENV_API_KEY,
|
|
221
|
+
ENV_MODEL, exe_path(), jd, os.path.join(jd, SERVE_FILE), int(FRESH_S)))
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
# 生效条件:先取 st=serve_state(jobs, fresh_s) 与 mdl=model_name(model);st["alive"] 为真且 mdl 非空时返回 state=HIVE;否则 allow_degrade 为真时返回 state=SUBAGENT 且 channel 取 channel 或 "harness-subagent";否则返回 state=CONFIGURE、transport=None 并附 setup_hint(jobs, why)。
|
|
225
|
+
def probe(jobs: str = "", model: str = "", fresh_s: float = FRESH_S,
|
|
226
|
+
allow_degrade: bool = False, channel: str = "") -> dict:
|
|
227
|
+
"""三级能力探测:hive(可派发)→ configure(提示配置)→ subagent(显式降级)。
|
|
228
|
+
|
|
229
|
+
判据只认**心跳 + 模型名**两项硬前提;缺任一即如实降级,绝不用相似度
|
|
230
|
+
(如「hive 目录存在」)冒充可用(资格由条件证据裁决,不由相似度裁决)。
|
|
231
|
+
"""
|
|
232
|
+
st = serve_state(jobs, fresh_s)
|
|
233
|
+
mdl = model_name(model)
|
|
234
|
+
if st["alive"] and mdl:
|
|
235
|
+
return {"state": HIVE, "transport": HIVE, "model": mdl, "jobs_dir": st["jobs_dir"],
|
|
236
|
+
"serve": st, "channel": "", "hint": ""}
|
|
237
|
+
why = st["reason"] if not st["alive"] else "serve 存活但未配置复核模型(%s)" % ENV_MODEL
|
|
238
|
+
if allow_degrade:
|
|
239
|
+
return {"state": SUBAGENT, "transport": SUBAGENT, "model": mdl,
|
|
240
|
+
"jobs_dir": st["jobs_dir"], "serve": st,
|
|
241
|
+
"channel": channel or "harness-subagent",
|
|
242
|
+
"hint": "已按 allow_degrade 降级到 harness 端子代理:请把 prompt 交给宿主子代理,"
|
|
243
|
+
"裁决经 verdicts 回填(蜂巢不可用原因:%s)" % why}
|
|
244
|
+
return {"state": CONFIGURE, "transport": None, "model": mdl,
|
|
245
|
+
"jobs_dir": st["jobs_dir"], "serve": st, "channel": "",
|
|
246
|
+
"hint": setup_hint(jobs, why)}
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
# 生效条件:state/transport/model/jobs_dir/serve/channel/hint 全部直接取自 probe(jobs, model, fresh_s, allow_degrade, channel) 的对应键,本函数不另做判活或模型判断,仅在 chain 文案中固定引用 int(FRESH_S) 与 ENV_MODEL。
|
|
250
|
+
def plan(jobs: str = "", model: str = "", fresh_s: float = FRESH_S,
|
|
251
|
+
allow_degrade: bool = False, channel: str = "") -> dict:
|
|
252
|
+
"""优先级链自描述(供 cg op=ccg action=units 与审计查看)。"""
|
|
253
|
+
p = probe(jobs, model, fresh_s, allow_degrade, channel)
|
|
254
|
+
return {"state": p["state"], "transport": p["transport"], "model": p["model"],
|
|
255
|
+
"jobs_dir": p["jobs_dir"], "serve": p["serve"], "channel": p["channel"],
|
|
256
|
+
"chain": [
|
|
257
|
+
{"order": 1, "transport": HIVE, "action": "派发 reflect/verify 单元并等待 result.json",
|
|
258
|
+
"when": ("jobs/_serve.json 心跳 < %ss 且(%s 已配置 **或调用方显式传 model**)"
|
|
259
|
+
% (int(FRESH_S), ENV_MODEL))},
|
|
260
|
+
{"order": 2, "transport": CONFIGURE, "action": "返回配置指引(不自动拉起、不假装通过)",
|
|
261
|
+
"when": "蜂巢不可用"},
|
|
262
|
+
{"order": 3, "transport": SUBAGENT, "action": "返回复核请求包,由 harness 端子代理执行并回填",
|
|
263
|
+
"when": "调用方显式 allow_degrade=True"},
|
|
264
|
+
],
|
|
265
|
+
"hint": p["hint"]}
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
# ---------------------------------------------------------------- 派发与收取
|
|
269
|
+
|
|
270
|
+
# 生效条件:无入参,恒返回 "h"+int(time.time()*1000)+"_"+uuid.uuid4().hex 前 6 位组成的字符串。
|
|
271
|
+
def _job_id() -> str:
|
|
272
|
+
"""同 _submit:serve 侧按 'h' 前缀识别任务目录。"""
|
|
273
|
+
return "h%d_%s" % (int(time.time() * 1000), uuid.uuid4().hex[:6])
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# 生效条件:cg.root 与 cg.cg.root 都取不到真值时不写、直接返回 None;取到 root 时向 root/LOG_NAME 追加一行 rec(副本,setdefault ts)的 JSON,写入抛 OSError 时被吞掉静默返回 None。
|
|
277
|
+
def _log(cg, rec: dict) -> None:
|
|
278
|
+
"""留痕 _units.jsonl(对齐 _crosscheck.jsonl / _backfill.jsonl 纪律)。"""
|
|
279
|
+
root = getattr(cg, "root", None) or getattr(getattr(cg, "cg", None), "root", None)
|
|
280
|
+
if not root:
|
|
281
|
+
return
|
|
282
|
+
try:
|
|
283
|
+
rec = dict(rec)
|
|
284
|
+
rec.setdefault("ts", int(time.time() * 1000))
|
|
285
|
+
with open(os.path.join(str(root), LOG_NAME), "a", encoding="utf-8") as f:
|
|
286
|
+
f.write(json.dumps(rec, ensure_ascii=False) + "\n")
|
|
287
|
+
except OSError:
|
|
288
|
+
pass
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# 生效条件:role 不在 ROLES 时返回 ok=False 的未知角色 error;否则 model_name(model) 为空时返回 ok=False 的未配置复核模型;否则 str(prompt or "").strip() 为空时返回 ok=False 的 prompt 为空;否则在 jobs_dir(jobs)/_job_id() 下写 spec.json 与 status.json(context_files 为真、temperature 非 None、extra 为真时才并入 spec),OSError 时返回 ok=False 的写入失败,全部成功返回 ok=True 与 job_id/job_dir/spec/model。
|
|
292
|
+
def submit(*, prompt: str, role: str = REFLECT, model: str = "", system_prompt: str = "",
|
|
293
|
+
context_files=None, timeout_s: int = DEFAULT_TIMEOUT_S,
|
|
294
|
+
max_tokens: int = DEFAULT_MAX_TOKENS, temperature=None, jobs: str = "",
|
|
295
|
+
actor: str = "", extra: dict = None, cg=None) -> dict:
|
|
296
|
+
"""写一条 LLM 委托型 job(spec.json + status.json,形态同 _submit);只写文件不起进程。"""
|
|
297
|
+
if role not in ROLES:
|
|
298
|
+
return {"ok": False, "error": "未知复核角色:%r(可选 %s)" % (role, list(ROLES))}
|
|
299
|
+
mdl = model_name(model)
|
|
300
|
+
if not mdl:
|
|
301
|
+
return {"ok": False, "error": "未配置复核模型:请设 %s 或显式传 model" % ENV_MODEL}
|
|
302
|
+
if not str(prompt or "").strip():
|
|
303
|
+
return {"ok": False, "error": "prompt 为空"}
|
|
304
|
+
jd, job_id = jobs_dir(jobs), _job_id()
|
|
305
|
+
d = os.path.join(jd, job_id)
|
|
306
|
+
spec = {"model": mdl, "user_prompt": str(prompt), "system_prompt": str(system_prompt or ""),
|
|
307
|
+
"timeout_s": int(timeout_s), "max_tokens": int(max_tokens),
|
|
308
|
+
"role": role, "unit_role": role}
|
|
309
|
+
if context_files:
|
|
310
|
+
spec["context_files"] = list(context_files)
|
|
311
|
+
if temperature is not None:
|
|
312
|
+
spec["temperature"] = temperature
|
|
313
|
+
if extra:
|
|
314
|
+
spec.update(extra)
|
|
315
|
+
try:
|
|
316
|
+
os.makedirs(d, exist_ok=True)
|
|
317
|
+
with open(os.path.join(d, SPEC_FILE), "w", encoding="utf-8") as f:
|
|
318
|
+
json.dump(spec, f, ensure_ascii=False)
|
|
319
|
+
with open(os.path.join(d, STATUS_FILE), "w", encoding="utf-8") as f:
|
|
320
|
+
json.dump({"job_id": job_id, "state": "pending",
|
|
321
|
+
"created_ts": int(time.time() * 1000), "started_ts": None,
|
|
322
|
+
"heartbeat_ts": None, "elapsed_s": 0.0, "timeout_s": int(timeout_s),
|
|
323
|
+
"model": mdl, "pid": None, "error": None}, f, ensure_ascii=False)
|
|
324
|
+
except OSError as exc:
|
|
325
|
+
return {"ok": False, "job_dir": d,
|
|
326
|
+
"error": "job 写入失败:%s: %s" % (type(exc).__name__, exc)}
|
|
327
|
+
_log(cg, {"action": "submit", "job_id": job_id, "role": role, "model": mdl,
|
|
328
|
+
"timeout_s": int(timeout_s), "actor": actor, "prompt_head": str(prompt)[:200]})
|
|
329
|
+
return {"ok": True, "job_id": job_id, "job_dir": d, "spec": spec,
|
|
330
|
+
"unit_role": role, "model": mdl}
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
# 生效条件:jobs_dir(jobs)/str(job_id or "") 不是目录时返回 state=missing、terminal=False 的目录不存在 error;是目录时读 STATUS_FILE(读失败则 status 置 None)并用其 state 覆盖 state/terminal(state 属 TERMINAL_STATES 才 terminal=True);RESULT_FILE 被 isfile 命中则 terminal=True、state=st or "done",解析抛 OSError/ValueError 时提前返回该 error;解析为 dict 时取 ok/content/error/usage/model,且 ok 为真而 content 去空白为空时把 ok 改 False 并写空正文 error,解析为非 dict 时 ok=True 且 content 为原值。
|
|
334
|
+
def poll(job_id: str, jobs: str = "") -> dict:
|
|
335
|
+
"""读 job 终态视图:**以 result.json 出现为终态主判据**,status.json 仅作辅助。"""
|
|
336
|
+
d = os.path.join(jobs_dir(jobs), str(job_id or ""))
|
|
337
|
+
out = {"job_id": job_id, "job_dir": d, "state": "missing", "terminal": False,
|
|
338
|
+
"ok": False, "content": None, "error": None, "status": None}
|
|
339
|
+
if not os.path.isdir(d):
|
|
340
|
+
out["error"] = "job 目录不存在:%s" % d
|
|
341
|
+
return out
|
|
342
|
+
sp = os.path.join(d, STATUS_FILE)
|
|
343
|
+
if os.path.isfile(sp):
|
|
344
|
+
try:
|
|
345
|
+
with open(sp, encoding="utf-8") as f:
|
|
346
|
+
out["status"] = json.load(f)
|
|
347
|
+
except (OSError, ValueError):
|
|
348
|
+
out["status"] = None
|
|
349
|
+
st = (out["status"] or {}).get("state")
|
|
350
|
+
if st:
|
|
351
|
+
out.update({"state": st, "terminal": st in TERMINAL_STATES})
|
|
352
|
+
rp = os.path.join(d, RESULT_FILE)
|
|
353
|
+
if os.path.isfile(rp):
|
|
354
|
+
out["state"] = st or "done"
|
|
355
|
+
out["terminal"] = True
|
|
356
|
+
try:
|
|
357
|
+
with open(rp, encoding="utf-8") as f:
|
|
358
|
+
res = json.load(f)
|
|
359
|
+
except (OSError, ValueError) as exc:
|
|
360
|
+
out["error"] = "result.json 不可读:%s" % type(exc).__name__
|
|
361
|
+
return out
|
|
362
|
+
if isinstance(res, dict):
|
|
363
|
+
out["ok"] = bool(res.get("ok"))
|
|
364
|
+
out["content"] = res.get("content")
|
|
365
|
+
out["error"] = res.get("error") or out["error"]
|
|
366
|
+
out["usage"] = res.get("usage")
|
|
367
|
+
out["model"] = res.get("model")
|
|
368
|
+
# 空正文**不得报成功**:reasoning 与正文共享 completion 预算,预算不足时
|
|
369
|
+
# job 仍自称 ok 但 content 为空 → 若不拦,会被误读成「复核单元无答复」
|
|
370
|
+
# (假死锁)。run() 早已有同等校验,此处补齐,消除两处口径不一致。
|
|
371
|
+
if out["ok"] and not str(out["content"] or "").strip():
|
|
372
|
+
out["ok"] = False
|
|
373
|
+
out["error"] = ("空正文:job 自称 ok 但 content 为空(多为 reasoning 吃尽"
|
|
374
|
+
"完成预算;提高 max_tokens,勿把预算不足当通道不可用)")
|
|
375
|
+
else:
|
|
376
|
+
out["ok"], out["content"] = True, res
|
|
377
|
+
return out
|
|
378
|
+
|
|
379
|
+
|
|
380
|
+
# 生效条件:循环 poll(job_id, jobs),结果 terminal 为真即补 waited_s 后返回;否则 time.time()-t0 >= float(timeout_s) 时返回 terminal=False、timeout=True 与超时 error;两者皆不满足则 sleep(float(poll_s)) 后重试(timeout_s=0 时首次 poll 非终态即超时返回)。
|
|
381
|
+
def wait(job_id: str, *, jobs: str = "", timeout_s: float = DEFAULT_TIMEOUT_S,
|
|
382
|
+
poll_s: float = DEFAULT_POLL_S) -> dict:
|
|
383
|
+
"""阻塞等终态;超时如实返回(不假装成功、不强杀 job)。"""
|
|
384
|
+
t0 = time.time()
|
|
385
|
+
while True:
|
|
386
|
+
cur = poll(job_id, jobs)
|
|
387
|
+
if cur.get("terminal"):
|
|
388
|
+
cur["waited_s"] = round(time.time() - t0, 3)
|
|
389
|
+
return cur
|
|
390
|
+
if (time.time() - t0) >= float(timeout_s):
|
|
391
|
+
cur.update({"terminal": False, "timeout": True, "waited_s": round(time.time() - t0, 3),
|
|
392
|
+
"error": "等待超时 %.0fs(job 仍在 %s)" % (float(timeout_s),
|
|
393
|
+
cur.get("state"))})
|
|
394
|
+
return cur
|
|
395
|
+
time.sleep(float(poll_s))
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
# 生效条件:submit(prompt=prompt, role=role, cg=cg, actor=actor, **kw) 的 ok 为假时返回 stage="submit" 的失败 dict(含 **sub);ok 为真时 wait(sub["job_id"], jobs=kw.get("jobs",""), timeout_s=wait_s),补 stage="wait"/job_id/unit_role/model,并把 ok 改为 res 的 ok 与 content 同时为真。
|
|
399
|
+
def run(*, prompt: str, role: str = REFLECT, cg=None, actor: str = "",
|
|
400
|
+
wait_s: float = DEFAULT_TIMEOUT_S, **kw) -> dict:
|
|
401
|
+
"""submit + wait 组合(阻塞式复核,MCP action=review 主路径)。"""
|
|
402
|
+
sub = submit(prompt=prompt, role=role, cg=cg, actor=actor, **kw)
|
|
403
|
+
if not sub.get("ok"):
|
|
404
|
+
return {"ok": False, "stage": "submit", "error": sub.get("error"), **sub}
|
|
405
|
+
res = wait(sub["job_id"], jobs=kw.get("jobs", ""), timeout_s=wait_s)
|
|
406
|
+
res.update({"stage": "wait", "job_id": sub["job_id"], "unit_role": role,
|
|
407
|
+
"model": sub.get("model")})
|
|
408
|
+
res["ok"] = bool(res.get("ok")) and bool(res.get("content"))
|
|
409
|
+
return res
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
# ---------------------------------------------------------------- 裁决解析与搬运
|
|
413
|
+
|
|
414
|
+
_FENCE_RE = re.compile(r"```(?:json)?\s*(.+?)\s*```", re.S)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
# 生效条件:raw 是 dict/list 时原样返回;否则取 str(raw or "").strip(),为空串(含 0/False/None 等假值)返回 None;否则依次尝试 _FENCE_RE 第 1 组、整段文本、首个 "{" 到末个 "}" 及首个 "[" 到末个 "]" 的切片,返回首个能 json.loads 成 dict 或 list 的候选;全部失败返回 None。
|
|
418
|
+
def _json_of(raw):
|
|
419
|
+
"""从单元输出抽第一个 JSON 对象/数组(容忍 ```json 围栏与前后噪声)。"""
|
|
420
|
+
if isinstance(raw, (dict, list)):
|
|
421
|
+
return raw
|
|
422
|
+
text = str(raw or "").strip()
|
|
423
|
+
if not text:
|
|
424
|
+
return None
|
|
425
|
+
cands = []
|
|
426
|
+
m = _FENCE_RE.search(text)
|
|
427
|
+
if m:
|
|
428
|
+
cands.append(m.group(1))
|
|
429
|
+
cands.append(text)
|
|
430
|
+
for opener, closer in (("{", "}"), ("[", "]")):
|
|
431
|
+
i, j = text.find(opener), text.rfind(closer)
|
|
432
|
+
if 0 <= i < j:
|
|
433
|
+
cands.append(text[i:j + 1])
|
|
434
|
+
for c in cands:
|
|
435
|
+
try:
|
|
436
|
+
v = json.loads(c)
|
|
437
|
+
except ValueError:
|
|
438
|
+
continue
|
|
439
|
+
if isinstance(v, (dict, list)):
|
|
440
|
+
return v
|
|
441
|
+
return None
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
# 生效条件:data=_json_of(raw) 为 list 时取 data[0](仅当它是 dict,否则 None);非 dict 时返回 verdict=DEFER、parsed=False;dict 时 word 取 verdict/decision/state/result 中首个真值后 strip().lower(),_VERDICT_MAP.get(word) 为 None 时返回 DEFER、parsed=True 并带 corr 与 reason,命中时返回该裁决及 reason、slot_corrections(取自 slot_corrections/corrections,非 dict 则置 {})、checks、raw 前 500 字符。
|
|
445
|
+
def verdict_of(raw) -> dict:
|
|
446
|
+
"""单元输出 → 裁决四态;解析不出 → DEFER(不猜测、不当通过)。"""
|
|
447
|
+
data = _json_of(raw)
|
|
448
|
+
if isinstance(data, list):
|
|
449
|
+
data = data[0] if data and isinstance(data[0], dict) else None
|
|
450
|
+
if not isinstance(data, dict):
|
|
451
|
+
return {"verdict": DEFER, "reason": "单元输出无法解析为裁决 JSON",
|
|
452
|
+
"slot_corrections": {}, "raw": str(raw)[:500], "parsed": False}
|
|
453
|
+
word = str(data.get("verdict") or data.get("decision") or data.get("state")
|
|
454
|
+
or data.get("result") or "").strip().lower()
|
|
455
|
+
reason = str(data.get("reason") or data.get("why") or data.get("detail") or "").strip()
|
|
456
|
+
corr = data.get("slot_corrections") or data.get("corrections") or {}
|
|
457
|
+
corr = corr if isinstance(corr, dict) else {}
|
|
458
|
+
got = _VERDICT_MAP.get(word)
|
|
459
|
+
if got is None:
|
|
460
|
+
return {"verdict": DEFER, "slot_corrections": corr, "parsed": True, "raw": str(raw)[:500],
|
|
461
|
+
"reason": "单元未给出可识别的裁决(%r)%s" % (word, (":" + reason) if reason else "")}
|
|
462
|
+
return {"verdict": got, "reason": reason, "slot_corrections": corr,
|
|
463
|
+
"checks": data.get("checks"), "raw": str(raw)[:500], "parsed": True}
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
# 生效条件:state==HIVE 时返回 "hive:<role>:<job_id 或 'unknown'>";state==SUBAGENT 时返回 "subagent:<role>:<channel 或 'harness'>";其余 state 返回空串。
|
|
467
|
+
def transport_name(state: str, role: str, job_id: str = "", channel: str = "") -> str:
|
|
468
|
+
"""裁决来源标识:**结构上不可能等于编译者**,保证 A 裁定「不得自证」不被误伤。"""
|
|
469
|
+
if state == HIVE:
|
|
470
|
+
return "hive:%s:%s" % (role, job_id or "unknown")
|
|
471
|
+
if state == SUBAGENT:
|
|
472
|
+
return "subagent:%s:%s" % (role, channel or "harness")
|
|
473
|
+
return ""
|
|
474
|
+
|
|
475
|
+
|
|
476
|
+
# 生效条件:unit 为假值时按 {} 处理;verdict=unit.get("verdict") or DEFER,verifier=transport_name(state, role, job_id, channel),evidence 取 unit 的 reason,为空则退回 str(unit["raw"])[:300],job_id 为真时再追加“(job=<job_id>)”;仅当 unit 的 slot_corrections 为真才带该键,仅当 compiled_by 与 verifier 皆非空且相等才置 self_verify=True。
|
|
477
|
+
def to_attest_args(unit: dict, *, state: str = "", role: str = REFLECT, job_id: str = "",
|
|
478
|
+
channel: str = "", compiled_by: str = "") -> dict:
|
|
479
|
+
"""单元裁决 → ccgc.attest(...) 入参(纯函数,离线可测)。
|
|
480
|
+
|
|
481
|
+
诚实边界:只做搬运与命名;裁决正确性由外部单元负责,本模块不为其背书。
|
|
482
|
+
"""
|
|
483
|
+
unit = unit or {}
|
|
484
|
+
verdict = unit.get("verdict") or DEFER
|
|
485
|
+
verifier = transport_name(state, role, job_id, channel)
|
|
486
|
+
evidence = str(unit.get("reason") or "")
|
|
487
|
+
if unit.get("raw") and not evidence:
|
|
488
|
+
evidence = str(unit["raw"])[:300]
|
|
489
|
+
if job_id:
|
|
490
|
+
evidence = "%s(job=%s)" % (evidence, job_id)
|
|
491
|
+
args = {"verdict": verdict, "verifier": verifier, "evidence": evidence}
|
|
492
|
+
if unit.get("slot_corrections"):
|
|
493
|
+
args["slot_corrections"] = unit["slot_corrections"]
|
|
494
|
+
if compiled_by and verifier and verifier == compiled_by:
|
|
495
|
+
args["self_verify"] = True
|
|
496
|
+
return args
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
# ---------------------------------------------------------------- 复核请求包
|
|
500
|
+
|
|
501
|
+
_REFLECT_TPL = """你是认知图记忆节点的**反思单元**(reflect)。下面是一份由 ccgc 编译出的
|
|
502
|
+
CCG 六要素候选(功能名/生效条件/子功能/执行/验证方式/不适用条件)。请逐项反思:
|
|
503
|
+
|
|
504
|
+
1) 六要素是否齐备,是否都能在「对话记录」里找到字面依据;
|
|
505
|
+
2) 「生效条件」四槽(场景/时窗/对象/前置)是否与实际适用范围一致,有无过度泛化;
|
|
506
|
+
3) 「不适用条件」(拒绝域)是否漏掉了明显该拒的情形;
|
|
507
|
+
4) 若有问题,给出**最小修正**(只改该字段,不重写)。
|
|
508
|
+
|
|
509
|
+
编译产物(JSON):
|
|
510
|
+
{digest}
|
|
511
|
+
|
|
512
|
+
原始对话记录(真源,引用必须出自此处):
|
|
513
|
+
{dialog}
|
|
514
|
+
|
|
515
|
+
只输出一个 JSON 对象,不要任何解释文字:
|
|
516
|
+
{{"verdict":"accept|drop|defer","reason":"一句话依据","slot_corrections":{{}},
|
|
517
|
+
"checks":[{{"element":"功能名","ok":true,"note":""}}]}}"""
|
|
518
|
+
|
|
519
|
+
_VERIFY_TPL = """你是独立**验证单元**(verify)。对下面这份 CCG 六要素候选与反思单元的结论
|
|
520
|
+
逐条复核:来源是否真实可追溯、结论是否被对话记录支持、修正是否越权(不得新增事实)。
|
|
521
|
+
|
|
522
|
+
**你只能否决或存疑,不得新增主张、不得改写事实**(可给出 slot_corrections 修正已有槽位)。
|
|
523
|
+
|
|
524
|
+
候选(JSON):
|
|
525
|
+
{digest}
|
|
526
|
+
|
|
527
|
+
反思单元结论:
|
|
528
|
+
{reflect_rows}
|
|
529
|
+
|
|
530
|
+
对话记录(真源):
|
|
531
|
+
{dialog}
|
|
532
|
+
|
|
533
|
+
只输出一个 JSON 对象:
|
|
534
|
+
{{"verdict":"accept|drop|defer","reason":"一句话依据","slot_corrections":{{}}}}"""
|
|
535
|
+
|
|
536
|
+
|
|
537
|
+
# 生效条件:digest is None 时返回 "{}";digest 是 str 时原样返回;否则先试 to_dict/as_dict 可调用方法并 json.dumps 其返回值(抛异常即跳出改走后续分支);是 dict 时 json.dumps(digest);其余取 vars(digest) 中不以 "_" 开头的属性 json.dumps(default=str)。
|
|
538
|
+
def _digest_of(digest) -> str:
|
|
539
|
+
if digest is None:
|
|
540
|
+
return "{}"
|
|
541
|
+
if isinstance(digest, str):
|
|
542
|
+
return digest
|
|
543
|
+
for attr in ("to_dict", "as_dict"):
|
|
544
|
+
fn = getattr(digest, attr, None)
|
|
545
|
+
if callable(fn):
|
|
546
|
+
try:
|
|
547
|
+
return json.dumps(fn(), ensure_ascii=False, indent=1)
|
|
548
|
+
except Exception: # noqa: BLE001
|
|
549
|
+
break
|
|
550
|
+
if isinstance(digest, dict):
|
|
551
|
+
return json.dumps(digest, ensure_ascii=False, indent=1)
|
|
552
|
+
return json.dumps({k: v for k, v in vars(digest).items() if not k.startswith("_")},
|
|
553
|
+
ensure_ascii=False, indent=1, default=str)
|
|
554
|
+
|
|
555
|
+
|
|
556
|
+
# 生效条件:role==VERIFY 选 _VERIFY_TPL,否则选 _REFLECT_TPL;reflect_rows 是 str 时直接作为 rows,否则 json.dumps(reflect_rows or [], ensure_ascii=False, indent=1);最终返回 tpl.format(digest=_digest_of(digest), dialog=str(dialog or "(未提供)")[:6000], reflect_rows=rows[:3000])。
|
|
557
|
+
def prompt_for(role: str, digest=None, *, dialog: str = "", reflect_rows="") -> str:
|
|
558
|
+
"""按角色生成复核请求包正文(reflect/verify 共用一处模板真源)。"""
|
|
559
|
+
tpl = _VERIFY_TPL if role == VERIFY else _REFLECT_TPL
|
|
560
|
+
rows = reflect_rows if isinstance(reflect_rows, str) else json.dumps(
|
|
561
|
+
reflect_rows or [], ensure_ascii=False, indent=1)
|
|
562
|
+
return tpl.format(digest=_digest_of(digest), dialog=str(dialog or "(未提供)")[:6000],
|
|
563
|
+
reflect_rows=rows[:3000])
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
# 生效条件:text 取 prompt 真值或 prompt_for(role, digest, dialog=dialog, reflect_rows=reflect_rows);pr=probe(jobs, model, allow_degrade=allow_degrade, channel=channel) 为 SUBAGENT 时原样返回未派发的 SUBAGENT 包、为 CONFIGURE 时返回未派发的 CONFIGURE 包;为 HIVE 时若 autostart 为真且 serve_state(jobs) 非 alive 先 autostart_serve(jobs),再 submit(...),submit 失败回 CONFIGURE 且把 error 拼进 hint,成功则给出 job_id,blocking=False 直接返回;blocking=True 时 wait(sub["job_id"], jobs=jobs, timeout_s=wait_s),res.ok 为假则 unit 记 DEFER 并附未产出有效结果的 hint,为真则 unit=verdict_of(res.get("content")),随后填 transport/attest/result_ok/waited_s 并 _log。
|
|
567
|
+
def review(*, prompt: str = "", role: str = REFLECT, digest=None, dialog: str = "",
|
|
568
|
+
reflect_rows="", node_id: str = "", jobs: str = "", model: str = "",
|
|
569
|
+
timeout_s: int = DEFAULT_TIMEOUT_S, allow_degrade: bool = False,
|
|
570
|
+
channel: str = "", wait_s: float = DEFAULT_TIMEOUT_S, blocking: bool = True,
|
|
571
|
+
cg=None, actor: str = "", autostart: bool = False) -> dict:
|
|
572
|
+
"""复核主入口:**蜂巢优先 → 提示配置 → 端子代理降级**(三态各自如实返回)。
|
|
573
|
+
|
|
574
|
+
返回统一形态:{state, role, node_id, transport, unit, attest, prompt, job_id, hint}
|
|
575
|
+
- state=hive :已派发;blocking=True 时等终态并给出 unit/attest;否则只给 job_id
|
|
576
|
+
- state=configure:**未派发**,hint 为配置指引(使用者裁定:不可用即提示配置)
|
|
577
|
+
- state=subagent :**未派发**,返回 prompt 包供宿主子代理执行并回填
|
|
578
|
+
"""
|
|
579
|
+
text = prompt or prompt_for(role, digest, dialog=dialog, reflect_rows=reflect_rows)
|
|
580
|
+
pr = probe(jobs, model, allow_degrade=allow_degrade, channel=channel)
|
|
581
|
+
base = {"role": role, "node_id": node_id, "prompt": text,
|
|
582
|
+
"transport": None, "unit": None, "attest": None,
|
|
583
|
+
"job_id": None, "hint": pr.get("hint") or "", "channel": pr.get("channel") or "",
|
|
584
|
+
"degrade": {"channel": channel or "harness-subagent",
|
|
585
|
+
"how": "宿主子代理执行 prompt → 裁决经 verdicts 回填 attest"}}
|
|
586
|
+
if pr["state"] == SUBAGENT:
|
|
587
|
+
return {"state": SUBAGENT, **base,
|
|
588
|
+
"degrade": {"available": True, "channel": channel or "harness-subagent",
|
|
589
|
+
"how": "把 prompt 交给宿主子代理,取其 JSON 裁决后调 "
|
|
590
|
+
"cg(op=ccg, action=attest, verdict=<accept|drop|defer>, "
|
|
591
|
+
"verifier=subagent:<role>:<channel>)"}}
|
|
592
|
+
if pr["state"] == CONFIGURE:
|
|
593
|
+
return {"state": CONFIGURE, **base,
|
|
594
|
+
"degrade": {"available": True, "channel": channel or "harness-subagent",
|
|
595
|
+
"how": "① 按 hint 配置蜂巢后重试;② 或带 allow_degrade=true 降级子代理"}}
|
|
596
|
+
if autostart and not serve_state(jobs)["alive"]:
|
|
597
|
+
pr["autostart"] = autostart_serve(jobs)
|
|
598
|
+
sub = submit(prompt=text, role=role, jobs=jobs, model=model, timeout_s=timeout_s,
|
|
599
|
+
cg=cg, actor=actor)
|
|
600
|
+
if not sub.get("ok"):
|
|
601
|
+
return {"state": CONFIGURE, **base, "hint": (pr.get("hint") or "") + "\n" + str(sub.get("error"))}
|
|
602
|
+
out = {"state": HIVE, **base, "job_id": sub["job_id"], "unit_role": role,
|
|
603
|
+
"model": sub.get("model")}
|
|
604
|
+
if not blocking:
|
|
605
|
+
return out
|
|
606
|
+
res = wait(sub["job_id"], jobs=jobs, timeout_s=wait_s)
|
|
607
|
+
unit = verdict_of(res.get("content")) if res.get("ok") else {
|
|
608
|
+
"verdict": DEFER, "reason": res.get("error") or "单元未返回可用结果",
|
|
609
|
+
"slot_corrections": {}, "parsed": False}
|
|
610
|
+
out["unit"] = unit
|
|
611
|
+
out["transport"] = transport_name(HIVE, role, sub["job_id"])
|
|
612
|
+
out["attest"] = to_attest_args(unit, state=HIVE, role=role, job_id=sub["job_id"])
|
|
613
|
+
out["result_ok"] = bool(res.get("ok"))
|
|
614
|
+
out["waited_s"] = res.get("waited_s")
|
|
615
|
+
if not res.get("ok"):
|
|
616
|
+
out["hint"] = "蜂巢 job 未产出有效结果:%s(裁决按 DEFER 处理,未假装通过)" % res.get("error")
|
|
617
|
+
_log(cg, {"action": "review", "job_id": sub["job_id"], "role": role,
|
|
618
|
+
"node_id": node_id, "actor": actor, "unit_verdict": unit.get("verdict"),
|
|
619
|
+
"result_ok": bool(res.get("ok"))})
|
|
620
|
+
return out
|
|
621
|
+
|
|
622
|
+
|
|
623
|
+
# ---------------------------------------------------------------- serve 拉起(显式)
|
|
624
|
+
|
|
625
|
+
# 生效条件:serve_state(jobs_dir(jobs)) 已 alive 时返回 started=False 的“serve 存活”;否则 exe_path() 未被 isfile 命中时返回 started=False 并提示先 cargo build --release;否则以 detached/新会话 Popen 拉起 exe serve --jobs jd 并把 stdout/stderr 写入 jd/_serve.log,Popen 抛 OSError 时返回 started=False 的拉起失败;拉起后在 float(wait_s) 内轮询到 alive 返回 started=True 的“serve 已拉起”,轮询超时仍返回 started=True 但标注心跳未就绪。
|
|
626
|
+
def autostart_serve(jobs: str = "", wait_s: float = 5.0) -> dict:
|
|
627
|
+
"""**显式**拉起 serve(默认不启用;使用者裁定:不可用即提示配置)。
|
|
628
|
+
|
|
629
|
+
形态同 hive_mcp._ensure_serve:detached + 独立日志,不阻塞调用方。
|
|
630
|
+
"""
|
|
631
|
+
jd = jobs_dir(jobs)
|
|
632
|
+
if serve_state(jd)["alive"]:
|
|
633
|
+
return {"started": False, "note": "serve 存活"}
|
|
634
|
+
exe = exe_path()
|
|
635
|
+
if not os.path.isfile(exe):
|
|
636
|
+
return {"started": False, "note": "未找到可执行文件 %s——先 cargo build --release" % exe}
|
|
637
|
+
kwargs = {}
|
|
638
|
+
if os.name == "nt":
|
|
639
|
+
kwargs["creationflags"] = subprocess.DETACHED_PROCESS | subprocess.CREATE_NO_WINDOW
|
|
640
|
+
else:
|
|
641
|
+
kwargs["start_new_session"] = True
|
|
642
|
+
try:
|
|
643
|
+
os.makedirs(jd, exist_ok=True)
|
|
644
|
+
with open(os.path.join(jd, "_serve.log"), "ab") as logf:
|
|
645
|
+
subprocess.Popen([exe, "serve", "--jobs", jd], stdout=logf, stderr=logf,
|
|
646
|
+
stdin=subprocess.DEVNULL, **kwargs)
|
|
647
|
+
except OSError as exc:
|
|
648
|
+
return {"started": False, "note": "拉起失败:%s: %s" % (type(exc).__name__, exc)}
|
|
649
|
+
t0 = time.time()
|
|
650
|
+
while time.time() - t0 < float(wait_s):
|
|
651
|
+
if serve_state(jd)["alive"]:
|
|
652
|
+
return {"started": True, "note": "serve 已拉起"}
|
|
653
|
+
time.sleep(0.1)
|
|
654
|
+
return {"started": True, "note": "serve 已拉起(心跳未就绪,稍后自愈)"}
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
# 生效条件:返回 dict 的 ok=p["state"]==HIVE,其中 p=plan(jobs)(model/fresh_s/allow_degrade/channel 全走默认),state/serve_alive/serve_age_s/chain/hint/model 取自该 p;jobs_dir 取 jobs_dir(jobs),exe_found 与 exe_path 取 exe_path() 是否被 isfile 命中,model_set=bool(model_name())(无参,读 ENV_MODEL),api_key_set=bool(os.environ.get(ENV_API_KEY)),env 记录 ENV_JOBS_DIR 与 ENV_MODEL 的原值。
|
|
658
|
+
def doctor(jobs: str = "") -> dict:
|
|
659
|
+
"""能力体检(形态对齐 hive_doctor):判活 + exe + 模型 + 优先级链。"""
|
|
660
|
+
jd = jobs_dir(jobs)
|
|
661
|
+
p = plan(jobs)
|
|
662
|
+
return {"ok": p["state"] == HIVE, "state": p["state"], "jobs_dir": jd,
|
|
663
|
+
"serve_alive": p["serve"]["alive"], "serve_age_s": p["serve"]["age_s"],
|
|
664
|
+
"exe_found": os.path.isfile(exe_path()), "exe_path": exe_path(),
|
|
665
|
+
"model_set": bool(model_name()), "model": p["model"],
|
|
666
|
+
"api_key_set": bool(os.environ.get(ENV_API_KEY)),
|
|
667
|
+
"env": {"HIVE_JOBS_DIR": os.environ.get(ENV_JOBS_DIR, ""),
|
|
668
|
+
"MDCG_UNIT_MODEL": os.environ.get(ENV_MODEL, "")},
|
|
668
669
|
"chain": p["chain"], "hint": p["hint"]}
|