argo-search 1.0.1 → 2.9.8
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/LICENSE +201 -21
- package/README.en.md +735 -0
- package/README.es.md +777 -0
- package/README.ja.md +777 -0
- package/README.ko.md +777 -0
- package/README.md +778 -320
- package/SKILL.md +135 -0
- package/assets/readme/hero.svg +121 -0
- package/assets/readme/made-with-beautify.svg +10 -0
- package/assets/readme/proof-routes.svg +73 -0
- package/assets/readme/why-better.svg +104 -0
- package/assets/readme/workflow.svg +83 -0
- package/backends/domain_profiles.json +2356 -96
- package/backends/engine_registry.yaml +3428 -503
- package/backends/query_synonyms_cn.json +35 -0
- package/backends/quota_profiles.json +2488 -160
- package/backends/source_types_cn.json +109 -0
- package/backends/text_lexicon.json +44 -0
- package/bin/argo +772 -0
- package/bin/argo.js +102 -39
- package/config.yaml +5139 -367
- package/cordis.patch.yml +21 -0
- package/data/countries.json +40 -0
- package/data/lang_matrix/lang_capability.json +842 -0
- package/data/lang_matrix/matrix_2026-09-10.json +11921 -0
- package/data/regions_cn.json +1 -0
- package/docs/ADDING_NEW_ENGINE.md +184 -0
- package/docs/ARGO_INTRO.md +124 -0
- package/docs/DATA_SOURCE_GAPS.md +81 -0
- package/docs/DESIGN_LOCAL_DATA_FUSION.md +90 -0
- package/docs/ENGINE_CATALOG.md +575 -0
- package/docs/MCP_SETUP.md +108 -0
- package/docs/PLATFORM_PATHS.md +111 -0
- package/docs/RELEASE_NOTES_v2.8.0.md +71 -0
- package/docs/RELEASE_NOTES_v2.8.2.md +63 -0
- package/docs/RELEASE_NOTES_v2.8.3.md +55 -0
- package/docs/RELEASE_NOTES_v2.8.4.md +79 -0
- package/docs/RELEASE_NOTES_v2.8.5.md +102 -0
- package/docs/RELEASE_NOTES_v2.8.6.md +66 -0
- package/docs/RELEASE_NOTES_v2.8.7.md +65 -0
- package/docs/RELEASE_NOTES_v2.8.8.md +67 -0
- package/docs/RELEASE_NOTES_v2.8.9.md +67 -0
- package/docs/RELEASE_NOTES_v2.9.0.md +64 -0
- package/docs/RELEASE_NOTES_v2.9.8.md +73 -0
- package/docs/SEARCH_ARCHIVE.md +115 -0
- package/docs/assets/architecture.svg +104 -0
- package/docs/assets/hero.svg +98 -0
- package/docs/engines/bangumi.md +27 -0
- package/docs/engines/biorxiv.md +27 -0
- package/docs/engines/clawhub.md +27 -0
- package/docs/engines/crt_sh.md +27 -0
- package/docs/engines/datacite.md +27 -0
- package/docs/engines/deps_dev.md +27 -0
- package/docs/engines/douban_movie.md +27 -0
- package/docs/engines/endoflife.md +27 -0
- package/docs/engines/flk_law.md +27 -0
- package/docs/engines/fxtwitter.md +27 -0
- package/docs/engines/google_news.md +27 -0
- package/docs/engines/gov_regulations.md +27 -0
- package/docs/engines/guqian.md +27 -0
- package/docs/engines/hackernews.md +27 -0
- package/docs/engines/iplant.md +27 -0
- package/docs/engines/keenable.md +27 -0
- package/docs/engines/met_museum.md +27 -0
- package/docs/engines/nasa_images.md +27 -0
- package/docs/engines/netease_music.md +27 -0
- package/docs/engines/npm.md +27 -0
- package/docs/engines/nvd.md +27 -0
- package/docs/engines/openreview.md +27 -0
- package/docs/engines/openstd.md +27 -0
- package/docs/engines/parallel_free.md +27 -0
- package/docs/engines/people_daily.md +27 -0
- package/docs/engines/realtime_index.md +27 -0
- package/docs/engines/sec_edgar.md +27 -0
- package/docs/engines/seltz.md +27 -0
- package/docs/engines/skillsmp.md +27 -0
- package/docs/engines/sspai.md +27 -0
- package/docs/engines/std_samr.md +27 -0
- package/docs/engines/train.md +27 -0
- package/docs/engines/un_comtrade.md +27 -0
- package/docs/engines/wikisource.md +27 -0
- package/docs/engines/zdic.md +27 -0
- package/docs/engines/zenodo.md +27 -0
- package/docs/engines/zhihu_hot_app.md +27 -0
- package/docs//344/270/272/344/273/200/344/271/210/351/200/211/346/213/251argo.md +176 -0
- package/engines/README.md +10 -0
- package/engines/_template_cli.yaml +39 -0
- package/engines/_template_http.yaml +37 -0
- package/engines/plugins/_template_plugin.py +50 -0
- package/engines/specs/_cisa_kev.yaml +54 -0
- package/engines/specs/_osv.yaml +63 -0
- package/engines/specs/aljazeera.yaml +43 -0
- package/engines/specs/antara.yaml +43 -0
- package/engines/specs/artic.yaml +20 -0
- package/engines/specs/aviation_weather.yaml +39 -0
- package/engines/specs/bangumi.yaml +21 -0
- package/engines/specs/biorxiv.yaml +24 -0
- package/engines/specs/carbon_intensity.yaml +32 -0
- package/engines/specs/cfets.yaml +41 -0
- package/engines/specs/cinii.yaml +44 -0
- package/engines/specs/clawhub.yaml +49 -0
- package/engines/specs/cleveland.yaml +19 -0
- package/engines/specs/cn_ai_news.yaml +43 -0
- package/engines/specs/core.yaml +35 -0
- package/engines/specs/crt_sh.yaml +38 -0
- package/engines/specs/ct24.yaml +43 -0
- package/engines/specs/datacite.yaml +27 -0
- package/engines/specs/datagov_uk.yaml +41 -0
- package/engines/specs/ddgs_images.yaml +45 -0
- package/engines/specs/deepseek_search.yaml +74 -0
- package/engines/specs/deezer.yaml +20 -0
- package/engines/specs/defillama.yaml +38 -0
- package/engines/specs/deps_dev.yaml +21 -0
- package/engines/specs/digup.yaml +36 -0
- package/engines/specs/doi.yaml +39 -0
- package/engines/specs/douban_movie.yaml +22 -0
- package/engines/specs/dw_news.yaml +47 -0
- package/engines/specs/egov_law.yaml +21 -0
- package/engines/specs/elpais.yaml +43 -0
- package/engines/specs/endoflife.yaml +21 -0
- package/engines/specs/energy_charts.yaml +21 -0
- package/engines/specs/factcheck_org.yaml +52 -0
- package/engines/specs/faz.yaml +43 -0
- package/engines/specs/federal_register.yaml +57 -0
- package/engines/specs/firecrawl.yaml +53 -0
- package/engines/specs/flk_law.yaml +24 -0
- package/engines/specs/folha.yaml +43 -0
- package/engines/specs/france24.yaml +44 -0
- package/engines/specs/full_fact.yaml +47 -0
- package/engines/specs/fxtwitter.yaml +36 -0
- package/engines/specs/gbfs_nyc.yaml +32 -0
- package/engines/specs/gdacs.yaml +21 -0
- package/engines/specs/gdelt.yaml +64 -0
- package/engines/specs/gleif.yaml +55 -0
- package/engines/specs/google_news.yaml +22 -0
- package/engines/specs/gov_regulations.yaml +38 -0
- package/engines/specs/guardian_rss.yaml +59 -0
- package/engines/specs/hkex.yaml +40 -0
- package/engines/specs/hurriyet.yaml +43 -0
- package/engines/specs/iplant.yaml +25 -0
- package/engines/specs/jikan.yaml +24 -0
- package/engines/specs/jolpica.yaml +20 -0
- package/engines/specs/k10plus.yaml +20 -0
- package/engines/specs/keenable.yaml +44 -0
- package/engines/specs/keenable_free.yaml +36 -0
- package/engines/specs/lefigaro.yaml +43 -0
- package/engines/specs/listenbrainz.yaml +19 -0
- package/engines/specs/matichon.yaml +43 -0
- package/engines/specs/met_museum.yaml +21 -0
- package/engines/specs/nasa_images.yaml +45 -0
- package/engines/specs/netease_music.yaml +38 -0
- package/engines/specs/nhk.yaml +43 -0
- package/engines/specs/nhtsa_vpic.yaml +20 -0
- package/engines/specs/noaa_swpc.yaml +20 -0
- package/engines/specs/nvd.yaml +38 -0
- package/engines/specs/obis.yaml +20 -0
- package/engines/specs/opencitations.yaml +52 -0
- package/engines/specs/openf1.yaml +21 -0
- package/engines/specs/openfoodfacts.yaml +45 -0
- package/engines/specs/openligadb.yaml +20 -0
- package/engines/specs/openreview.yaml +37 -0
- package/engines/specs/openstd.yaml +21 -0
- package/engines/specs/people_daily.yaml +22 -0
- package/engines/specs/realtime_index.yaml +34 -0
- package/engines/specs/ror.yaml +20 -0
- package/engines/specs/satnogs.yaml +20 -0
- package/engines/specs/sec_edgar.yaml +46 -0
- package/engines/specs/shfe.yaml +39 -0
- package/engines/specs/skillsmp.yaml +50 -0
- package/engines/specs/sogou_weixin_browser.yaml +30 -0
- package/engines/specs/soilgrids.yaml +25 -0
- package/engines/specs/sspai.yaml +36 -0
- package/engines/specs/stackexchange.yaml +46 -0
- package/engines/specs/std_samr.yaml +21 -0
- package/engines/specs/tass.yaml +43 -0
- package/engines/specs/tavily_free.yaml +56 -0
- package/engines/specs/tle_mirror.yaml +21 -0
- package/engines/specs/train.yaml +37 -0
- package/engines/specs/tvmaze.yaml +20 -0
- package/engines/specs/twitter_syndication.yaml +31 -0
- package/engines/specs/un_comtrade.yaml +23 -0
- package/engines/specs/unpaywall.yaml +54 -0
- package/engines/specs/vnpress.yaml +43 -0
- package/engines/specs/weather.yaml +32 -0
- package/engines/specs/who_don.yaml +21 -0
- package/engines/specs/who_gho.yaml +20 -0
- package/engines/specs/wikimedia_commons.yaml +34 -0
- package/engines/specs/wikisource.yaml +22 -0
- package/engines/specs/worms.yaml +19 -0
- package/engines/specs/x_trending.yaml +34 -0
- package/engines/specs/yna.yaml +43 -0
- package/engines/specs/ynet.yaml +43 -0
- package/engines/specs/yuanbao.yaml +93 -0
- package/engines/specs/zbmath.yaml +40 -0
- package/engines/specs/zdic.yaml +22 -0
- package/engines/specs/zenodo.yaml +27 -0
- package/engines/specs/zhihu_hot_app.yaml +35 -0
- package/mcp/clients.yaml +106 -0
- package/package.json +55 -12
- package/packages/dsh-plugin/README.md +152 -0
- package/packages/dsh-plugin/cordis.patch.yml +48 -0
- package/packages/dsh-plugin/dsh/client.js +1533 -0
- package/packages/dsh-plugin/dsh/diagnostics.js +54 -0
- package/packages/dsh-plugin/dsh/index.js +527 -0
- package/packages/dsh-plugin/dsh/native-tools.mjs +749 -0
- package/packages/dsh-plugin/dsh/runner.js +666 -0
- package/packages/dsh-plugin/dsh/wide-research.js +878 -0
- package/packages/dsh-plugin/package.json +38 -0
- package/packages/dsh-plugin/scripts/sync-local.sh +70 -0
- package/packages/dsh-plugin/test/client.test.js +406 -0
- package/packages/dsh-plugin/test/config.test.js +30 -0
- package/packages/dsh-plugin/test/diagnostics.test.js +28 -0
- package/packages/dsh-plugin/test/index.test.js +1382 -0
- package/references/query-templates.md +96 -0
- package/references/query-templates.yaml +118 -0
- package/scripts/ab_eval.py +219 -0
- package/scripts/ab_eval_p0p1.py +266 -0
- package/scripts/adaptive.py +294 -70
- package/scripts/answer.py +154 -0
- package/scripts/archive_run.py +591 -0
- package/scripts/argo_engine_registry.py +172 -0
- package/scripts/argo_paths.py +728 -0
- package/scripts/article.py +136 -0
- package/scripts/article_meta.py +131 -0
- package/scripts/arxiv_source.py +201 -0
- package/scripts/badcase_ledger.py +252 -0
- package/scripts/batch_probe.py +241 -0
- package/scripts/benchmark.py +19 -0
- package/scripts/bounded_run.py +144 -0
- package/scripts/browser_auth.py +323 -0
- package/scripts/budget.py +247 -0
- package/scripts/budget_cli.py +93 -0
- package/scripts/build_release_assets.sh +65 -0
- package/scripts/burstiness_detector.py +147 -0
- package/scripts/cache.py +1066 -67
- package/scripts/cache_guard.py +271 -0
- package/scripts/cache_key_vdom.py +56 -0
- package/scripts/cache_similarity.py +170 -0
- package/scripts/caliber_isolation.py +195 -0
- package/scripts/calibrate_lowquality.py +210 -0
- package/scripts/candidate_envelope.py +366 -0
- package/scripts/chrome_cdp.py +871 -0
- package/scripts/ci_drift_gate.py +90 -0
- package/scripts/circuit_breaker.py +389 -0
- package/scripts/citations.py +334 -0
- package/scripts/cite_cli.py +59 -0
- package/scripts/cjk_tokens.py +95 -0
- package/scripts/clarify.py +47 -24
- package/scripts/cli_io.py +240 -0
- package/scripts/config.py +683 -45
- package/scripts/config_cache.py +402 -0
- package/scripts/conn_pool.py +220 -0
- package/scripts/content_boundary.py +46 -0
- package/scripts/content_security.py +685 -0
- package/scripts/content_signals.py +751 -0
- package/scripts/crawl.py +74 -35
- package/scripts/cross_lingual_trace.py +293 -0
- package/scripts/daemon.py +866 -0
- package/scripts/digup_bridge.py +214 -0
- package/scripts/dispatch_result.py +98 -0
- package/scripts/engine_admission.py +366 -0
- package/scripts/engine_dispatch.py +982 -0
- package/scripts/engine_env.py +539 -0
- package/scripts/engine_failure.py +411 -0
- package/scripts/engine_families.py +738 -0
- package/scripts/engine_policy.py +218 -0
- package/scripts/engine_requires.py +190 -0
- package/scripts/engine_status.py +322 -0
- package/scripts/engine_validate.py +638 -0
- package/scripts/engines.py +799 -294
- package/scripts/engines_base.py +1521 -0
- package/scripts/engines_builders.py +310 -0
- package/scripts/engines_builders_batch10.py +204 -0
- package/scripts/engines_builders_batch11.py +174 -0
- package/scripts/engines_builders_batch12.py +103 -0
- package/scripts/engines_builders_batch13.py +340 -0
- package/scripts/engines_builders_batch14.py +656 -0
- package/scripts/engines_builders_batch15.py +249 -0
- package/scripts/engines_builders_batch9.py +1468 -0
- package/scripts/engines_builders_cn.py +2283 -0
- package/scripts/engines_builders_data.py +2923 -0
- package/scripts/engines_builders_data_macro.py +775 -0
- package/scripts/engines_builders_feeds.py +255 -0
- package/scripts/engines_builders_intl.py +1239 -0
- package/scripts/engines_builders_keyless.py +111 -0
- package/scripts/engines_builders_search.py +440 -0
- package/scripts/engines_builders_tech.py +1359 -0
- package/scripts/evidence.py +620 -166
- package/scripts/evidence_loop.py +624 -0
- package/scripts/evidence_tier.py +298 -0
- package/scripts/except_sets.py +25 -0
- package/scripts/extract.py +55 -16
- package/scripts/fact_align.py +207 -0
- package/scripts/fact_crosscheck.py +230 -0
- package/scripts/fetch.py +25 -12
- package/scripts/fetch_browser.py +87 -0
- package/scripts/fetch_jsrun.py +122 -0
- package/scripts/fetch_quality.py +225 -0
- package/scripts/fetch_render_tinyfish.py +117 -0
- package/scripts/fetch_v3.py +1804 -0
- package/scripts/focus_extract.py +350 -0
- package/scripts/fulltext_store.py +169 -0
- package/scripts/fxtwitter_api.py +325 -0
- package/scripts/gen_engine_catalog.py +364 -0
- package/scripts/gen_native_tools.py +91 -0
- package/scripts/gen_routing_snapshot.py +195 -0
- package/scripts/health_check.py +140 -402
- package/scripts/health_probe.py +23 -8
- package/scripts/hot_state.py +134 -0
- package/scripts/http_client.py +1053 -0
- package/scripts/image_ops.py +430 -0
- package/scripts/image_vision/vision_probe.swift +126 -0
- package/scripts/install.ps1 +166 -0
- package/scripts/install.sh +221 -0
- package/scripts/job.py +1186 -0
- package/scripts/jump_resolver.py +235 -0
- package/scripts/lang_capability.py +150 -0
- package/scripts/lang_detect.py +289 -0
- package/scripts/lang_matrix_probe.py +329 -0
- package/scripts/lang_pref.py +311 -0
- package/scripts/link_source.py +340 -0
- package/scripts/local_image.py +970 -0
- package/scripts/local_seek.py +402 -0
- package/scripts/macro_countries.py +97 -0
- package/scripts/matrix_search_eval.py +1187 -0
- package/scripts/mcp_compact.py +234 -0
- package/scripts/mcp_diag.py +8 -3
- package/scripts/mcp_handlers.py +492 -0
- package/scripts/mcp_handlers_surface.py +157 -0
- package/scripts/mcp_launch.sh +124 -0
- package/scripts/mcp_local.py +241 -0
- package/scripts/mcp_server.py +125 -419
- package/scripts/mcp_setup.py +431 -0
- package/scripts/mcp_tools.py +331 -0
- package/scripts/mcp_transport.py +191 -0
- package/scripts/mcp_warm.py +127 -0
- package/scripts/min_version_scan.py +335 -0
- package/scripts/net_proxy.py +258 -0
- package/scripts/network_aware.py +152 -0
- package/scripts/output_transparency.py +200 -0
- package/scripts/paid_policy.py +98 -0
- package/scripts/paper.py +274 -0
- package/scripts/pdf_extract.py +518 -0
- package/scripts/phrase_filter.py +66 -0
- package/scripts/plan.py +422 -0
- package/scripts/postprocess_signals.py +150 -0
- package/scripts/pre-commit +48 -0
- package/scripts/query_enhance.py +157 -0
- package/scripts/query_operators.py +196 -0
- package/scripts/query_rewriter.py +116 -7
- package/scripts/query_signals.py +300 -0
- package/scripts/query_templates.py +167 -0
- package/scripts/query_understanding.py +411 -0
- package/scripts/query_variants.py +298 -0
- package/scripts/quota.py +633 -76
- package/scripts/rank_signals.py +775 -0
- package/scripts/ranking_eval.py +319 -0
- package/scripts/readability_extract.py +433 -0
- package/scripts/recompute.py +415 -0
- package/scripts/recovery.py +616 -0
- package/scripts/recovery_l0.py +160 -0
- package/scripts/recovery_runner.py +150 -0
- package/scripts/redskill/redskill_engine.py +332 -0
- package/scripts/regression_p0p1.py +318 -0
- package/scripts/replay_eval.py +658 -0
- package/scripts/rerank_tfidf.py +225 -0
- package/scripts/research.py +607 -403
- package/scripts/research_cli.py +361 -0
- package/scripts/research_dossier.py +492 -0
- package/scripts/research_expand.py +169 -0
- package/scripts/research_gates.py +272 -0
- package/scripts/research_report.py +209 -0
- package/scripts/research_strategy.py +37 -0
- package/scripts/research_work_packages.py +195 -0
- package/scripts/result_lang.py +311 -0
- package/scripts/retry_policy.py +76 -0
- package/scripts/robots_guard.py +259 -0
- package/scripts/route.py +921 -254
- package/scripts/route_bangs.py +40 -0
- package/scripts/route_cache.py +243 -0
- package/scripts/route_combo.py +917 -0
- package/scripts/route_domains.py +341 -0
- package/scripts/route_lang.py +605 -0
- package/scripts/route_log.py +63 -0
- package/scripts/route_policy.py +250 -0
- package/scripts/rrf_classic.py +66 -0
- package/scripts/screenshot.py +73 -0
- package/scripts/search.py +886 -406
- package/scripts/search_attribution.py +185 -0
- package/scripts/search_benchmark.py +407 -0
- package/scripts/search_cli.py +640 -0
- package/scripts/search_entry.py +395 -0
- package/scripts/search_output.py +690 -0
- package/scripts/search_pipeline.py +926 -0
- package/scripts/search_rank.py +991 -0
- package/scripts/search_types.py +129 -16
- package/scripts/seek_locator.py +68 -0
- package/scripts/semantic_evidence.py +391 -0
- package/scripts/serp_guard.py +336 -0
- package/scripts/serp_kill_log.py +74 -0
- package/scripts/single_flight.py +120 -0
- package/scripts/social_engines/__init__.py +10 -0
- package/scripts/social_engines/bilibili_engine.py +131 -0
- package/scripts/social_engines/hackernews_engine.py +113 -0
- package/scripts/social_engines/reddit_engine.py +172 -0
- package/scripts/social_engines/twitter_engine.py +397 -0
- package/scripts/social_engines/v2ex_engine.py +101 -0
- package/scripts/social_engines/weibo_engine.py +128 -0
- package/scripts/social_engines/xiaohongshu_engine.py +137 -0
- package/scripts/social_engines/zhihu_engine.py +139 -0
- package/scripts/social_research.py +201 -0
- package/scripts/sogou_weixin_browser.py +318 -0
- package/scripts/source_ledger.py +249 -0
- package/scripts/stage_timing.py +58 -0
- package/scripts/stats_cli.py +107 -0
- package/scripts/straggler_policy.py +60 -0
- package/scripts/stylometry_detector.py +231 -0
- package/scripts/sync_backends.py +353 -0
- package/scripts/sync_installs.py +29 -0
- package/scripts/template_cli.py +127 -0
- package/scripts/text_lexicon.py +72 -0
- package/scripts/tfidf_router.py +109 -37
- package/scripts/time_utils.py +233 -0
- package/scripts/topic_research_profiles.py +643 -0
- package/scripts/train.py +737 -0
- package/scripts/tweet.py +596 -0
- package/scripts/url_canon.py +217 -0
- package/scripts/url_optimize.py +56 -0
- package/scripts/url_safety.py +236 -0
- package/scripts/usage_log.py +116 -0
- package/scripts/usage_log_clean.py +113 -0
- package/scripts/v2ex_nodes.py +311 -0
- package/scripts/variant_recall.py +188 -0
- package/scripts/watch.py +205 -0
- package/scripts/wechat_article.py +258 -0
- package/scripts/wide_research.py +447 -0
- package/scripts/wx.py +349 -0
- package/scripts/x_article_fetch.py +141 -0
- package/scripts/x_search.py +234 -0
- package/scripts/x_trending.py +189 -0
- package/scripts/yaml_load.py +67 -0
- package/scripts/zhihu_quota.py +139 -0
- package/sub-skills/ego-search/SKILL.md +253 -0
- package/sub-skills/ego-search/scripts/ego_search.py +800 -0
- package/sub-skills/ego-search/scripts/merge.py +226 -0
- package/sub-skills/ego-search/scripts/quality.py +64 -0
- package/sub-skills/ego-search/scripts/runtime.py +172 -0
- package/sub-skills/ego-search/scripts/safety.py +109 -0
- package/sub-skills/ego-search/scripts/serp_spec.py +109 -0
- package/sub-skills/ego-search/scripts/webbridge_adapter.py +374 -0
- package/sub-skills/js-run/SKILL.md +67 -0
- package/sub-skills/js-run/scripts/jsrun.py +112 -0
- package/sub-skills/js-run/scripts/shim.js +188 -0
- package/sub-skills/local-search/SKILL.md +50 -53
- package/sub-skills/local-search/bm25.py +186 -0
- package/sub-skills/local-search/cli_runner.py +331 -0
- package/sub-skills/local-search/config.yaml +152 -55
- package/sub-skills/local-search/engine_registry.py +91 -26
- package/sub-skills/local-search/{health_check.py → local_health_check.py} +140 -10
- package/sub-skills/local-search/local_search_adapter.py +13 -2
- package/sub-skills/local-search/parse_maps.yaml +40 -42
- package/sub-skills/local-search/parsers.py +328 -0
- package/sub-skills/local-search/search_v3.py +716 -242
- package/sub-skills/local-search/smart_router.py +47 -7
- package/sub-skills/local-seek/SKILL.md +110 -0
- package/sub-skills/local-seek/config/domains.yaml +20 -0
- package/sub-skills/local-seek/scripts/eval_rank.py +216 -0
- package/sub-skills/local-seek/scripts/eval_seek.py +224 -0
- package/sub-skills/local-seek/scripts/seek.py +1465 -0
- package/sub-skills/local-seek/scripts/seek_frecency.py +126 -0
- package/sub-skills/local-seek/scripts/seek_fts.py +430 -0
- package/sub-skills/local-seek/scripts/seek_rank.py +197 -0
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""search_entry.py — 搜索的入口两段:准备(prepare)与调度(dispatch)。
|
|
3
|
+
|
|
4
|
+
与 search_pipeline 的分工(四个阶段合起来就是一次搜索的全过程):
|
|
5
|
+
|
|
6
|
+
prepare 请求侧整理 + 缓存查询(命中即返回存档响应,不再打网络)
|
|
7
|
+
dispatch 引擎编排(并发/串行、重试、熔断、结局分类)——实现在 engine_dispatch
|
|
8
|
+
postprocess 融合 + 13 个加工阶段(search_pipeline)
|
|
9
|
+
finalize 缓存写 + 记账 + 对外响应(search_pipeline)
|
|
10
|
+
|
|
11
|
+
## 为什么把 prepare/dispatch 单独成模块
|
|
12
|
+
|
|
13
|
+
它们是**唯一**会打网络、也是唯一依赖「可打桩入口」的两段:测试靠
|
|
14
|
+
`patch.object(search, "engine_search" / "get_engines" / "_missing_env_for" /
|
|
15
|
+
"_FAST_TOTAL_BUDGET_S" / "_PRIMARY_GRACE_S")` 换掉引擎与预算。这些入口与常量
|
|
16
|
+
**按值传入**(`_SearchHooks`),不让本模块反向 import search——直连绑定会让补丁
|
|
17
|
+
静默失效(假引擎不被调用、真网络被打开)。
|
|
18
|
+
|
|
19
|
+
execute_search 因此只剩编排:prepare → (命中则返回)→ dispatch → postprocess →
|
|
20
|
+
finalize,五行。
|
|
21
|
+
|
|
22
|
+
## 边界
|
|
23
|
+
|
|
24
|
+
本模块不 import http_client / engines_base;网络只经由传入的 hooks 与
|
|
25
|
+
engine_dispatch。
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from __future__ import annotations
|
|
29
|
+
|
|
30
|
+
import time
|
|
31
|
+
from search_types import slot_record as dataclass, slot_field as field, slot_replace as replace
|
|
32
|
+
from typing import Any, Callable, Optional
|
|
33
|
+
|
|
34
|
+
from engine_dispatch import run_dispatch
|
|
35
|
+
from usage_log import emit as _emit_usage
|
|
36
|
+
from search_output import _collect_errors
|
|
37
|
+
from search_pipeline import _SearchRequest, _SearchRun
|
|
38
|
+
from search_types import Stage
|
|
39
|
+
from stage_timing import StageTiming, tick as _tick, tock as _tock
|
|
40
|
+
from time_utils import (
|
|
41
|
+
is_time_capable as _is_time_capable,
|
|
42
|
+
normalize_time_window as _normalize_time_window,
|
|
43
|
+
sort_results_by_time as _sort_results,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _log(message: str) -> None:
|
|
48
|
+
"""默认静默的调试出口;仅在真正需要记录时才引入 logging。
|
|
49
|
+
|
|
50
|
+
与 search_output._log 同一范式。本模块的 prepare 曾有两处**函数内**裸
|
|
51
|
+
`import logging`:CPython 在编译期就把 `logging` 定为 prepare 的局部名,
|
|
52
|
+
任何早于它们的分支再加一处 `logging.getLogger(...)`,另外两处立刻编译成
|
|
53
|
+
LOAD_FAST → UnboundLocalError,而它们全在 except 处理器内,处理器再抛会
|
|
54
|
+
顶替掉原本被 fail-open 吞掉的错误。模块级不留绑定:既无局部遮蔽,也不把
|
|
55
|
+
logging→traceback→dataclasses→inspect(实测 21 ms)拖进 import search
|
|
56
|
+
的必经之路。
|
|
57
|
+
"""
|
|
58
|
+
import logging
|
|
59
|
+
logging.getLogger("unified_search").debug(message)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@dataclass(frozen=True)
|
|
63
|
+
class _SearchHooks:
|
|
64
|
+
"""可打桩的入口与常量(按值传入,见模块 docstring)。"""
|
|
65
|
+
|
|
66
|
+
engine_search: Any
|
|
67
|
+
available_engines: Any
|
|
68
|
+
get_cost_factor: Any
|
|
69
|
+
get_engines: Any
|
|
70
|
+
get_execution_config: Any
|
|
71
|
+
missing_env_for: Any
|
|
72
|
+
classify_outcome: Any
|
|
73
|
+
note_quota_exhausted: Any
|
|
74
|
+
per_engine_budget_s: float
|
|
75
|
+
fast_budget_s: float
|
|
76
|
+
auto_budget_s: float
|
|
77
|
+
primary_grace_s: float
|
|
78
|
+
straggler_grace_s: float
|
|
79
|
+
serial_stagger_s: float
|
|
80
|
+
deep_budget_s: float | None = None
|
|
81
|
+
# 尾宽分层函数(可选,默认 None = 固定尾宽):dataclass 默认值字段只能
|
|
82
|
+
# 排在无默认值字段之后,故放在末尾。
|
|
83
|
+
straggler_tail_fn: Callable[[str, float], float] | None = None
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@dataclass(frozen=True)
|
|
87
|
+
class _Prepared:
|
|
88
|
+
"""准备阶段的产出——两种结局显式分开,不用哨兵值:
|
|
89
|
+
|
|
90
|
+
- 命中缓存:`cached` 非空(调用方直接返回它,不再打网络),req/run 为空;
|
|
91
|
+
- 未命中:`req`/`run` 就位,交给 dispatch。
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
cached: dict[str, Any] | None = None
|
|
95
|
+
req: _SearchRequest | None = None
|
|
96
|
+
run: _SearchRun | None = None
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def prepare(query: str, decision: dict[str, Any], max_results: int,
|
|
101
|
+
timeout: int, depth: str, cache: Any, skip_cache: bool,
|
|
102
|
+
*, mode: str = "auto", since: str | None = None,
|
|
103
|
+
until: str | None = None, sort: str = "relevance",
|
|
104
|
+
on_progress: Optional[Callable[[Stage, dict[str, Any]], None]] = None,
|
|
105
|
+
engine_domain: str | None = None,
|
|
106
|
+
engine_sub_domain: str | None = None,
|
|
107
|
+
timing: StageTiming | None = None,
|
|
108
|
+
hooks: _SearchHooks) -> _Prepared:
|
|
109
|
+
"""请求侧整理 + 缓存查询;命中时 `cached` 非空(调用方直接返回它)。
|
|
110
|
+
|
|
111
|
+
段内顺序即契约:查询理解 → 词形规范化 → 进度事件 → 网络感知超时 →
|
|
112
|
+
时间窗归一化 → 缓存键 → 缓存查询。
|
|
113
|
+
"""
|
|
114
|
+
domain = decision.get("domain") or "general"
|
|
115
|
+
engine_label = decision.get("engine", "auto")
|
|
116
|
+
engines_combo = decision.get("engines_combo", decision.get("engines", [engine_label]))
|
|
117
|
+
# 防御:过滤空引擎名(空串会在 registry 查无 → 空结果 → 熔断空键 '')。
|
|
118
|
+
# 全空时保底 anysearch,防止下方 engines[0] IndexError(route 层已保证
|
|
119
|
+
# combo 非空,此处仅防畸形 decision 直接调用 execute_search)。
|
|
120
|
+
engines = [e for e in engines_combo if e] or ["anysearch"]
|
|
121
|
+
parallel = decision.get("parallel", False) and len(engines) > 1
|
|
122
|
+
|
|
123
|
+
# P0-001:查询理解 — clean_query 用于检索,exclude_terms 用于融合后过滤
|
|
124
|
+
exclude_terms: list[str] = []
|
|
125
|
+
retrieval_query = query
|
|
126
|
+
qu = None
|
|
127
|
+
try:
|
|
128
|
+
from query_understanding import _understand_cached as understand
|
|
129
|
+
qu = understand(query)
|
|
130
|
+
exclude_terms = qu.exclude_terms
|
|
131
|
+
# 查询操作符 -词/-"短语" 的排除项汇合(2026-10-17 query_operators):
|
|
132
|
+
# 与否定理解共用同一「融合后过滤」通道,去重保序。
|
|
133
|
+
_op_excl = ((decision or {}).get("operators") or {}).get("exclude_terms") or []
|
|
134
|
+
for t in _op_excl:
|
|
135
|
+
if t and t not in exclude_terms:
|
|
136
|
+
exclude_terms.append(t)
|
|
137
|
+
# 仅当去否定片段后仍有实义内容时才替换检索词,避免空检索
|
|
138
|
+
if qu.clean_query and qu.clean_query.strip():
|
|
139
|
+
retrieval_query = qu.clean_query
|
|
140
|
+
except ImportError:
|
|
141
|
+
pass # query_understanding 不可用
|
|
142
|
+
except Exception as e:
|
|
143
|
+
_log(f"查询理解跳过: {type(e).__name__}")
|
|
144
|
+
|
|
145
|
+
# 词形规范化:全角→半角、拆斜杠、压多余空格(提升精确源命中,治型号/日期分隔符)
|
|
146
|
+
try:
|
|
147
|
+
from query_enhance import normalize_query
|
|
148
|
+
retrieval_query = normalize_query(retrieval_query)
|
|
149
|
+
except ImportError:
|
|
150
|
+
pass
|
|
151
|
+
|
|
152
|
+
if on_progress:
|
|
153
|
+
on_progress(Stage.START, {"query": query})
|
|
154
|
+
|
|
155
|
+
# 网络环境感知:慢网放大超时预算(避免误杀),快网收紧(更快响应)
|
|
156
|
+
_eff_timeout = timeout
|
|
157
|
+
try:
|
|
158
|
+
from network_aware import adjusted_timeout, network_profile
|
|
159
|
+
_eff_timeout = adjusted_timeout(timeout, engines)
|
|
160
|
+
if _eff_timeout != timeout:
|
|
161
|
+
_log(
|
|
162
|
+
f"网络感知超时: {timeout}s → {_eff_timeout}s "
|
|
163
|
+
f"({network_profile(engines).get('network')})",
|
|
164
|
+
)
|
|
165
|
+
except ImportError:
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
# 时间窗归一化:下推/缓存键用归一化 ISO(相对值转绝对日期),
|
|
169
|
+
# 后过滤用 epoch 秒;非法输入保持原样下推、不参与后过滤。
|
|
170
|
+
since_iso, until_iso, since_ts, until_ts = _normalize_time_window(since, until)
|
|
171
|
+
|
|
172
|
+
# 缓存键的引擎维度取**请求侧身份**(用户点名的引擎,或 auto),不取
|
|
173
|
+
# 路由出来的 engines_combo。
|
|
174
|
+
#
|
|
175
|
+
# 为什么(2026-09-19 实测):combo 是决策结果,会被 adaptive 学习器按上一次
|
|
176
|
+
# 搜索的成败逐次改写。拿结果当键就是「用缓存让缓存失效」——同一查询连跑
|
|
177
|
+
# 两次,进键的引擎串从 `anysearch+octen` 变成 `exa+octen`、从 `byted+...`
|
|
178
|
+
# 变成 `local_bing+...`,20 条样本里 6 条重复查询(30%)因此白跑一遍网络,
|
|
179
|
+
# 而查询、域、档位全都没变。
|
|
180
|
+
#
|
|
181
|
+
# 语义边界:用户点名 `--engine pypi` 时键里就是 pypi(显式约束必须隔离,
|
|
182
|
+
# 这正是 v2.4.2 那条修复要保的东西);`auto` 时键里是 auto——「用自动路由
|
|
183
|
+
# 搜这个查询」本身就是请求,具体挑了哪几个引擎是实现细节,由 TTL 兜住
|
|
184
|
+
# 时效,并原样保留在缓存载荷里供追溯。
|
|
185
|
+
cache_engine_key = decision.get("engine_request") or "auto"
|
|
186
|
+
# 引擎级垂直域并入缓存键:--domain/--sub_domain 改变了发给引擎的请求,
|
|
187
|
+
# 同 query 在不同 domain 下的结果集不同。不隔离就会把「不限域」的结果
|
|
188
|
+
# 当成「限定金融域」的答案发回去——而这两个开关此前连请求都没带上,
|
|
189
|
+
# 静默退化成通用搜索(同一个坑的另一半)。
|
|
190
|
+
if engine_domain:
|
|
191
|
+
cache_engine_key += f"|ed={engine_domain}"
|
|
192
|
+
if engine_sub_domain:
|
|
193
|
+
cache_engine_key += f"|esd={engine_sub_domain}"
|
|
194
|
+
# 查询操作符并入缓存键:clean_query 是键的主体,若不把指令本身入键,
|
|
195
|
+
# 受限查询与无约束查询会互串缓存(site: 最危险——用户写了约束却可能
|
|
196
|
+
# 命中未过滤的旧条目)。after/before 已由下方 since/until 隔离。
|
|
197
|
+
try:
|
|
198
|
+
from query_operators import operator_cache_suffix
|
|
199
|
+
cache_engine_key += operator_cache_suffix(
|
|
200
|
+
(decision or {}).get("operators"))
|
|
201
|
+
except ImportError:
|
|
202
|
+
pass
|
|
203
|
+
# 时间窗并入缓存键:同一 query 不同 since/until 不串缓存;
|
|
204
|
+
# 用归一化 ISO(7d 与等价绝对日期共享缓存;相对窗跨天自然过期不串旧数据)。
|
|
205
|
+
# 仅当组合内含带时间能力引擎时隔离:无时间字段引擎忽略时间窗、结果相同,
|
|
206
|
+
# 隔离只会降低命中率(7d/30d 查 octen/anysearch 命中同一缓存)。
|
|
207
|
+
time_aware = any(_is_time_capable(e) for e in engines)
|
|
208
|
+
if since_iso and time_aware:
|
|
209
|
+
cache_engine_key += f"|since={since_iso}"
|
|
210
|
+
if until_iso and time_aware:
|
|
211
|
+
cache_engine_key += f"|until={until_iso}"
|
|
212
|
+
|
|
213
|
+
if on_progress:
|
|
214
|
+
on_progress(Stage.ROUTING, {"domain": domain, "engine": engine_label, "engines": engines})
|
|
215
|
+
|
|
216
|
+
# combo 缓存命中(含 depth + 柔性命中)
|
|
217
|
+
if not skip_cache:
|
|
218
|
+
t_cache_start = time.time()
|
|
219
|
+
_tk_cache = _tick(timing)
|
|
220
|
+
hit = cache.get(query, cache_engine_key, max_results, domain=domain,
|
|
221
|
+
mode=mode, depth=depth)
|
|
222
|
+
_tock(timing, "cache_lookup", _tk_cache)
|
|
223
|
+
if hit:
|
|
224
|
+
cache_elapsed = int((time.time() - t_cache_start) * 1000)
|
|
225
|
+
if on_progress:
|
|
226
|
+
on_progress(Stage.CACHE_HIT, {"cache_level": hit.get("_cache_level", "L?")})
|
|
227
|
+
tfidf_scores = decision.get("tfidf_scores", [])
|
|
228
|
+
if tfidf_scores and all(s.get("score", 0) == 0 for s in tfidf_scores):
|
|
229
|
+
tfidf_scores = []
|
|
230
|
+
# 排序在缓存读出后、返回前:缓存内容保持 score 序,sort 只改展示顺序
|
|
231
|
+
hit_results = _sort_results(hit.get("results", []), sort)
|
|
232
|
+
# 命中时一律报**产出这批结果的那次运行**的组合与理由,而不是本次
|
|
233
|
+
# 路由的。此前两者恒等(组合就在缓存键里),这条区分不存在;键改成
|
|
234
|
+
# 请求身份后,同一查询两次运行可以路由到不同组合,而本次路由根本
|
|
235
|
+
# 没执行——报它等于报一个没跑过的计划,还会与同样来自缓存的
|
|
236
|
+
# engines_used / engine_outcomes 自相矛盾。
|
|
237
|
+
cached_combo = (hit.get("engines_combo") or hit.get("engines")
|
|
238
|
+
or engines)
|
|
239
|
+
_hit = {
|
|
240
|
+
"query": query, "engine": (cached_combo or engines)[0],
|
|
241
|
+
"engines": cached_combo,
|
|
242
|
+
"engines_combo": cached_combo, "cached": True,
|
|
243
|
+
"cache_level": hit.get("_cache_level", "L?"),
|
|
244
|
+
"domain": domain, "elapsed_ms": cache_elapsed,
|
|
245
|
+
"tfidf_scores": tfidf_scores,
|
|
246
|
+
"route_reason": hit.get("route_reason") or decision.get("reason"),
|
|
247
|
+
"login_hint": decision.get("login_hint"),
|
|
248
|
+
"results": hit_results,
|
|
249
|
+
"count": len(hit_results),
|
|
250
|
+
"engines_used": hit.get("engines_used") or engines,
|
|
251
|
+
"mode": mode, "depth": depth,
|
|
252
|
+
"reranker": "skipped_cache",
|
|
253
|
+
"engine_outcomes": hit.get("engine_outcomes") or [],
|
|
254
|
+
"errors": _collect_errors({}, hit.get("engine_outcomes") or []),
|
|
255
|
+
"time_filtered": 0,
|
|
256
|
+
}
|
|
257
|
+
# 软命中披露:L2 语义命中返回的是**另一条查询**的载荷,不标出来
|
|
258
|
+
# 就与精确命中无法区分——调用方会以为这就是本查询的缓存。同样遵循
|
|
259
|
+
# 「不适用就整个键缺席」(见下方漏斗注释):精确命中下这三个键不
|
|
260
|
+
# 存在,不写成 null。
|
|
261
|
+
if hit.get("_semantic_hit"):
|
|
262
|
+
_hit["semantic_hit"] = True
|
|
263
|
+
_hit["semantic_query"] = hit.get("_semantic_query")
|
|
264
|
+
_hit["semantic_similarity"] = hit.get("_semantic_similarity")
|
|
265
|
+
# 缓存命中时漏斗记账沿用存档值(它描述的是上一次真实抓取)。
|
|
266
|
+
# 存档里没有(该条写入于引入漏斗之前)就**整个键缺席**,不写成
|
|
267
|
+
# null——null 会被读成「漏斗算出来是空」,而缺席只表示「这次没有
|
|
268
|
+
# 这个数据」。两种档位(默认/agent)必须同一形态,否则同一件事
|
|
269
|
+
# 有两种表述。
|
|
270
|
+
if hit.get("funnel") is not None:
|
|
271
|
+
_hit["funnel"] = hit["funnel"]
|
|
272
|
+
if timing is not None:
|
|
273
|
+
_hit["timing"] = timing.summary()
|
|
274
|
+
return _Prepared(cached=_hit)
|
|
275
|
+
try:
|
|
276
|
+
from circuit_breaker import get_breaker
|
|
277
|
+
breaker = get_breaker()
|
|
278
|
+
except ImportError:
|
|
279
|
+
breaker = None
|
|
280
|
+
|
|
281
|
+
return _Prepared(req=_SearchRequest(
|
|
282
|
+
query=query, decision=decision, engines=engines,
|
|
283
|
+
engines_combo=engines_combo, domain=domain, mode=mode, depth=depth,
|
|
284
|
+
timeout=timeout, max_results=max_results, retrieval_query=retrieval_query,
|
|
285
|
+
parallel=parallel, eff_timeout=_eff_timeout,
|
|
286
|
+
exclude_terms=exclude_terms, qu=qu, since_iso=since_iso,
|
|
287
|
+
until_iso=until_iso, since_ts=since_ts, until_ts=until_ts,
|
|
288
|
+
time_aware=time_aware, skip_cache=skip_cache, timing=timing,
|
|
289
|
+
on_progress=on_progress, sort=sort, cache=cache,
|
|
290
|
+
engine_label=engine_label, cache_engine_key=cache_engine_key,
|
|
291
|
+
emit_usage_log=_emit_usage, breaker=breaker,
|
|
292
|
+
engine_domain=engine_domain, engine_sub_domain=engine_sub_domain,
|
|
293
|
+
), run=_SearchRun(raw_results={}, engine_outcomes=[], merged=[]))
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
def dispatch(req: _SearchRequest, run: _SearchRun, hooks: _SearchHooks) -> _SearchRun:
|
|
297
|
+
"""引擎编排:打网络、记账、返回填好 dispatch 字段的运行状态。
|
|
298
|
+
|
|
299
|
+
run_dispatch 的入口与常量按值传入(见模块 docstring)。
|
|
300
|
+
"""
|
|
301
|
+
query = req.query
|
|
302
|
+
decision = req.decision
|
|
303
|
+
engines = req.engines
|
|
304
|
+
domain = req.domain
|
|
305
|
+
mode, depth = req.mode, req.depth
|
|
306
|
+
max_results, timeout = req.max_results, req.timeout
|
|
307
|
+
skip_cache, cache = req.skip_cache, req.cache
|
|
308
|
+
since_iso, until_iso = req.since_iso, req.until_iso
|
|
309
|
+
timing, on_progress = req.timing, req.on_progress
|
|
310
|
+
retrieval_query = req.retrieval_query
|
|
311
|
+
parallel = req.parallel
|
|
312
|
+
_eff_timeout = req.eff_timeout
|
|
313
|
+
if on_progress:
|
|
314
|
+
on_progress(Stage.SEARCHING, {"engines": engines})
|
|
315
|
+
|
|
316
|
+
t0 = time.time()
|
|
317
|
+
# 单调钟基准:预算窗不随 NTP 跳变失真(engine_dispatch 整套换钟,见其垫片注释)
|
|
318
|
+
t0_mono = time.monotonic()
|
|
319
|
+
_tk_dispatch = _tick(timing)
|
|
320
|
+
# 配额批次在这里建、在融合后的 D6 补搜之后才 flush:中间所有 _ingest
|
|
321
|
+
# (含补搜)都要记进同一批,提前 flush 会让补搜引擎的记账落不了盘。
|
|
322
|
+
#
|
|
323
|
+
# import 放在函数内:quota 模块在 import 期就 ensure_state_dir()(mkdir)。
|
|
324
|
+
# 放模块级意味着每次 argo 调用——含纯缓存命中、根本不建批次的路径——
|
|
325
|
+
# 都要碰一次文件系统。批量对象只可能在本函数被创建,没理由让不建批次的
|
|
326
|
+
# 路径付这笔钱。
|
|
327
|
+
from quota import _QuotaBatch
|
|
328
|
+
quota_batch = _QuotaBatch()
|
|
329
|
+
# 引擎编排(并发/串行调度、重试、熔断、结局分类)整段在 engine_dispatch。
|
|
330
|
+
# 入口与常量**按值传入**而非让那边直接 import search:测试靠
|
|
331
|
+
# patch.object(search, "engine_search" / "get_engines" / "_missing_env_for" /
|
|
332
|
+
# "_FAST_TOTAL_BUDGET_S" / "_PRIMARY_GRACE_S") 换掉它们,直连绑定会让补丁
|
|
333
|
+
# 静默失效(假引擎不被调用、真网络被打开)。
|
|
334
|
+
_dispatch = run_dispatch(
|
|
335
|
+
query=query, retrieval_query=retrieval_query, engines=engines,
|
|
336
|
+
decision=decision, parallel=parallel,
|
|
337
|
+
domain=domain, mode=mode, depth=depth,
|
|
338
|
+
max_results=max_results, timeout=timeout, net_timeout=_eff_timeout,
|
|
339
|
+
skip_cache=skip_cache, cache=cache, breaker=req.breaker,
|
|
340
|
+
since_iso=since_iso, until_iso=until_iso, t0=t0, t0_mono=t0_mono,
|
|
341
|
+
engine_search=hooks.engine_search,
|
|
342
|
+
get_engines_fn=hooks.get_engines,
|
|
343
|
+
get_execution_config_fn=hooks.get_execution_config,
|
|
344
|
+
missing_env_for=hooks.missing_env_for,
|
|
345
|
+
classify_outcome=hooks.classify_outcome,
|
|
346
|
+
quota_batch=quota_batch,
|
|
347
|
+
note_quota_exhausted=hooks.note_quota_exhausted,
|
|
348
|
+
per_engine_budget_s=hooks.per_engine_budget_s,
|
|
349
|
+
fast_budget_s=hooks.fast_budget_s,
|
|
350
|
+
auto_budget_s=hooks.auto_budget_s,
|
|
351
|
+
deep_budget_s=hooks.deep_budget_s,
|
|
352
|
+
primary_grace_s=hooks.primary_grace_s,
|
|
353
|
+
straggler_grace_s=hooks.straggler_grace_s,
|
|
354
|
+
straggler_tail_fn=hooks.straggler_tail_fn,
|
|
355
|
+
serial_stagger_s=hooks.serial_stagger_s,
|
|
356
|
+
engine_domain=req.engine_domain,
|
|
357
|
+
engine_sub_domain=req.engine_sub_domain,
|
|
358
|
+
)
|
|
359
|
+
raw_results = _dispatch.raw_results
|
|
360
|
+
engine_outcomes = _dispatch.engine_outcomes
|
|
361
|
+
engine_latency = _dispatch.engine_latency
|
|
362
|
+
wasted_ms = _dispatch.wasted_ms
|
|
363
|
+
useful_ms = _dispatch.useful_ms
|
|
364
|
+
dispatch_tail = {
|
|
365
|
+
"first_sufficient_ms": _dispatch.first_sufficient_ms,
|
|
366
|
+
"tail_wait_ms": _dispatch.tail_wait_ms,
|
|
367
|
+
"abandoned_engine_ms": _dispatch.abandoned_engine_ms,
|
|
368
|
+
}
|
|
369
|
+
early_stopped = _dispatch.early_stopped
|
|
370
|
+
budget_used_ms = _dispatch.budget_used_ms
|
|
371
|
+
budget_total_ms = _dispatch.budget_total_ms
|
|
372
|
+
# 融合后的 D6 补搜要用同一套「跑单引擎 + 入账」,钩子由此取回
|
|
373
|
+
_run_one = _dispatch.run_one
|
|
374
|
+
_ingest = _dispatch.ingest
|
|
375
|
+
|
|
376
|
+
elapsed = int((time.time() - t0) * 1000)
|
|
377
|
+
_tock(timing, "dispatch", _tk_dispatch)
|
|
378
|
+
_tk_fusion = _tick(timing)
|
|
379
|
+
return replace(
|
|
380
|
+
run,
|
|
381
|
+
raw_results=raw_results,
|
|
382
|
+
engine_outcomes=engine_outcomes,
|
|
383
|
+
engine_latency=engine_latency,
|
|
384
|
+
wasted_ms=wasted_ms,
|
|
385
|
+
useful_ms=useful_ms,
|
|
386
|
+
dispatch_tail=dispatch_tail,
|
|
387
|
+
early_stopped=early_stopped,
|
|
388
|
+
budget_used_ms=budget_used_ms,
|
|
389
|
+
budget_total_ms=budget_total_ms,
|
|
390
|
+
elapsed=elapsed,
|
|
391
|
+
tk_fusion=_tk_fusion,
|
|
392
|
+
quota_batch=quota_batch,
|
|
393
|
+
run_one=_run_one,
|
|
394
|
+
ingest=_ingest,
|
|
395
|
+
)
|