argo-search 1.0.1 → 2.9.7
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 +822 -0
- package/README.es.md +864 -0
- package/README.ja.md +864 -0
- package/README.ko.md +864 -0
- package/README.md +867 -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/settings-keys.png +0 -0
- package/assets/readme/settings-tools.png +0 -0
- package/assets/readme/why-better.svg +104 -0
- package/assets/readme/workflow.svg +83 -0
- package/backends/domain_profiles.json +2308 -96
- package/backends/engine_registry.yaml +3314 -503
- package/backends/query_synonyms_cn.json +35 -0
- package/backends/quota_profiles.json +2409 -161
- package/backends/source_types_cn.json +83 -0
- package/backends/text_lexicon.json +44 -0
- package/bin/argo +703 -0
- package/bin/argo.js +71 -39
- package/config.yaml +4976 -363
- 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 +564 -0
- package/docs/MCP_SETUP.md +106 -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/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/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/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 +31 -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/google_news.yaml +22 -0
- package/engines/specs/gov_regulations.yaml +38 -0
- package/engines/specs/guardian_rss.yaml +59 -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/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/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/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/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 +74 -0
- package/package.json +51 -12
- package/packages/dsh-plugin/README.md +134 -0
- package/packages/dsh-plugin/cordis.patch.yml +48 -0
- package/packages/dsh-plugin/dsh/client.js +1244 -0
- package/packages/dsh-plugin/dsh/index.js +2290 -0
- package/packages/dsh-plugin/dsh/native-tools.mjs +743 -0
- package/packages/dsh-plugin/package.json +38 -0
- package/packages/dsh-plugin/test/client.test.js +232 -0
- package/packages/dsh-plugin/test/config.test.js +30 -0
- package/packages/dsh-plugin/test/index.test.js +1338 -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 +271 -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/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/burstiness_detector.py +147 -0
- package/scripts/cache.py +1078 -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/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_security.py +685 -0
- package/scripts/content_signals.py +730 -0
- package/scripts/crawl.py +74 -35
- package/scripts/daemon.py +866 -0
- package/scripts/digup_bridge.py +214 -0
- package/scripts/engine_admission.py +366 -0
- package/scripts/engine_dispatch.py +1019 -0
- package/scripts/engine_env.py +534 -0
- package/scripts/engine_failure.py +411 -0
- package/scripts/engine_families.py +732 -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 +778 -294
- package/scripts/engines_base.py +1521 -0
- package/scripts/engines_builders.py +298 -0
- package/scripts/engines_builders_batch10.py +159 -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_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_search.py +440 -0
- package/scripts/engines_builders_tech.py +1360 -0
- package/scripts/evidence.py +588 -162
- package/scripts/evidence_loop.py +592 -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 +1779 -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 +184 -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 +0 -0
- package/scripts/image_vision/vision_probe.swift +126 -0
- package/scripts/install.ps1 +148 -0
- package/scripts/install.sh +206 -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_engines.py +321 -0
- package/scripts/local_image.py +970 -0
- package/scripts/local_seek.py +366 -0
- package/scripts/macro_countries.py +82 -0
- package/scripts/matrix_search_eval.py +1105 -0
- package/scripts/mcp_diag.py +8 -3
- package/scripts/mcp_handlers.py +1074 -0
- package/scripts/mcp_handlers_surface.py +157 -0
- package/scripts/mcp_launch.sh +122 -0
- package/scripts/mcp_server.py +118 -417
- package/scripts/mcp_setup.py +407 -0
- package/scripts/mcp_tools.py +330 -0
- package/scripts/mcp_transport.py +191 -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/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 +488 -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/redskill/redskill_engine.py +332 -0
- package/scripts/regression_p0p1.py +318 -0
- package/scripts/replay_eval.py +640 -0
- package/scripts/rerank_tfidf.py +225 -0
- package/scripts/research.py +591 -403
- package/scripts/research_cli.py +361 -0
- package/scripts/research_dossier.py +492 -0
- package/scripts/research_expand.py +146 -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/robots_guard.py +259 -0
- package/scripts/route.py +921 -254
- package/scripts/route_bangs.py +40 -0
- package/scripts/route_cache.py +225 -0
- package/scripts/route_combo.py +910 -0
- package/scripts/route_domains.py +328 -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 +897 -405
- package/scripts/search_attribution.py +88 -0
- package/scripts/search_benchmark.py +407 -0
- package/scripts/search_cli.py +627 -0
- package/scripts/search_entry.py +389 -0
- package/scripts/search_output.py +606 -0
- package/scripts/search_pipeline.py +1077 -0
- package/scripts/search_rank.py +991 -0
- package/scripts/search_types.py +27 -12
- package/scripts/seek_locator.py +68 -0
- package/scripts/semantic_evidence.py +215 -0
- package/scripts/serp_guard.py +228 -0
- package/scripts/serp_kill_log.py +51 -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 +95 -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 +402 -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/sub-skills/ego-search/SKILL.md +253 -0
- package/sub-skills/ego-search/references/browser-runtime.md +43 -0
- package/sub-skills/ego-search/references/install.md +67 -0
- package/sub-skills/ego-search/references/original-ego-upgrade.md +51 -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/ego-search/tests/test_query_normalize.py +68 -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/js-run/tests/fixtures/challenge_like.js +27 -0
- package/sub-skills/js-run/tests/test_jsrun.py +165 -0
- package/sub-skills/local-search/SKILL.md +50 -53
- package/sub-skills/local-search/bm25.py +162 -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/search_v3.py +1182 -65
- 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/references/auto-behaviors.md +24 -0
- package/sub-skills/local-seek/references/fd-mdfind-recipes.md +62 -0
- package/sub-skills/local-seek/references/git-integration.md +54 -0
- package/sub-skills/local-seek/references/remote-handoff.md +46 -0
- package/sub-skills/local-seek/references/rg-recipes.md +96 -0
- package/sub-skills/local-seek/references/strategies.md +52 -0
- package/sub-skills/local-seek/references/structural-search.md +59 -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 +193 -0
- package/sub-skills/local-seek/tests/test_content_rank.py +222 -0
- package/sub-skills/local-seek/tests/test_determinism_20261006.py +145 -0
- package/sub-skills/local-seek/tests/test_noise_tier.py +101 -0
- package/sub-skills/local-seek/tests/test_pcre2_probe.py +136 -0
- package/sub-skills/local-seek/tests/test_rank_pinyin.py +77 -0
- package/sub-skills/local-seek/tests/test_regression_20261003.py +169 -0
- package/sub-skills/local-seek/tests/test_regression_20261006.py +146 -0
- package/sub-skills/local-seek/tests/test_seek_degradation.py +111 -0
- package/sub-skills/local-seek/tests/test_seek_fts.py +313 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""route_bangs.py — DuckDuckGo Bangs 路由解析(!gh react → github 搜 react)。
|
|
3
|
+
|
|
4
|
+
2026-09-28 从 route.py 拆出:route.py 撞 1000 行体积门禁,而 Bangs 是
|
|
5
|
+
自包含的一小块「查表 + 首 token 解析」,与路由主流程只通过一个函数对接,
|
|
6
|
+
是门禁意义上最便宜的一刀。纯路由层逻辑:解析出目标引擎后走用户指定
|
|
7
|
+
引擎分支,不碰查询改写(那是 query_rewriter.py 的事)。
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
# !bang → 引擎名。映射目标必须是 engines.py 已注册的引擎名;写错的键只在
|
|
13
|
+
# 搜索时以「未知引擎」暴露——启动路径不加注册表校验(低频热路径零开销),
|
|
14
|
+
# 一致性由 tests/test_route_bangs.py 的注册冒烟钉住。
|
|
15
|
+
_BANGS_MAP: dict[str, str] = {
|
|
16
|
+
"!g": "local_bing",
|
|
17
|
+
"!gh": "github",
|
|
18
|
+
"!so": "stackoverflow",
|
|
19
|
+
"!w": "wikipedia",
|
|
20
|
+
"!gmaps": "local_openstreetmap",
|
|
21
|
+
}
|
|
22
|
+
# 注:!yt 不收录——原稿(9044621)映射到 google,而 google 引擎未注册
|
|
23
|
+
# (is_registered 实测 False),是带进来的死映射;等真有视频源再按注册名加回。
|
|
24
|
+
# 映射表只收已注册目标,由 tests/test_route_bangs.py 的注册冒烟钉住。
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def resolve_bangs(query: str) -> tuple[str, str] | None:
|
|
28
|
+
"""解析首 token Bang:!gh react → ("github", "react")。
|
|
29
|
+
|
|
30
|
+
只处理首 token,大小写不敏感(!GH 等价 !gh);未收录的 Bang 返回
|
|
31
|
+
None(走正常路由)。裸 Bang(无剩余查询)也解析——引擎点名成立,
|
|
32
|
+
空查询交由调用方按既有引擎分支的空串语义处理。
|
|
33
|
+
"""
|
|
34
|
+
if not query.startswith("!"):
|
|
35
|
+
return None
|
|
36
|
+
bang, sep, remainder = query.partition(" ")
|
|
37
|
+
target = _BANGS_MAP.get(bang.lower())
|
|
38
|
+
if not target:
|
|
39
|
+
return None
|
|
40
|
+
return target, (remainder.strip() if sep else "")
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""route_cache.py — 路由决策的跨进程缓存(存储层)。
|
|
3
|
+
|
|
4
|
+
为什么需要(2026-09-17 实测):route_query 的**首次调用**要付约 103 ms 的
|
|
5
|
+
进程级初始化——238 条域正则编译 33 ms(而跑完全部匹配只要 0.2 ms)、惰性导入、
|
|
6
|
+
引擎环境/准入与 TF-IDF 装载;同进程内的后续调用只要 3.7 ms。CLI 每次调用都是
|
|
7
|
+
新进程,于是这笔启动税每次重付。实测:跳过一次 route_query 后,缓存命中的
|
|
8
|
+
一次完整搜索只要 26 ms(对比 route 首调 137 ms + 执行 3 ms)。
|
|
9
|
+
|
|
10
|
+
判据为什么与 config 磁盘缓存不同:那一层的产物被当作**事实**(db_path 等),
|
|
11
|
+
必须逐字节正确,所以用内容摘要;这一层的产物是**优化结果**,偏差的后果只是
|
|
12
|
+
一段时间内引擎排序不最优,且有 TTL 与下游失败分型兜底,故用 config_stamp()
|
|
13
|
+
这个既有的 mtime 综合戳(registry 热加载同款)——键计算从约 5 ms 降到 0.1 ms。
|
|
14
|
+
|
|
15
|
+
本模块只管**存储**(键、指纹、读写、清理);「什么时候用缓存」是编排决策,
|
|
16
|
+
留在 route.route_query_cached——那是它唯一的调用方,放这里会绕成
|
|
17
|
+
route_cache → route → route_cache 的循环导入。
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
import time
|
|
23
|
+
from typing import Any
|
|
24
|
+
|
|
25
|
+
# ── 路由决策缓存(跨进程) ─────────────────────────────────────────────────────
|
|
26
|
+
#
|
|
27
|
+
# 为什么需要(2026-09-17 实测):route_query 的**首次调用**要付约 103 ms 的
|
|
28
|
+
# 进程级初始化——238 条域正则编译 33 ms(而跑完全部匹配只要 0.2 ms)、惰性导入、
|
|
29
|
+
# 引擎环境/准入与 TF-IDF 装载;同进程内的后续调用只要 3.7 ms。CLI 每次调用都是
|
|
30
|
+
# 新进程,于是这笔启动税每次重付。实测:跳过一次 route_query 后,缓存命中的
|
|
31
|
+
# 一次完整搜索只要 26 ms(对比 route 首调 137 ms + 执行 3 ms)。
|
|
32
|
+
#
|
|
33
|
+
# 判据为什么与 config 磁盘缓存不同:那一层的产物被当作**事实**(db_path 等),
|
|
34
|
+
# 必须逐字节正确,所以用内容摘要;这一层的产物是**优化结果**,偏差的后果只是
|
|
35
|
+
# 一段时间内引擎排序不最优,且有 TTL 与下游失败分型兜底,故用 config_stamp()
|
|
36
|
+
# 这个既有的 mtime 综合戳(registry 热加载同款)——键计算从约 5 ms 降到 0.1 ms。
|
|
37
|
+
|
|
38
|
+
_ROUTE_CACHE_SCHEMA = 1
|
|
39
|
+
# TTL 只兜自适应学习器(adaptive.db)的渐进漂移——影响路由的持久状态
|
|
40
|
+
# (config 改动 / 额度耗尽 / 熔断禁用)都在指纹里,变了键就换。原值 300 s
|
|
41
|
+
# 让隔了几分钟的重复查询白付整笔 route_query 启动税(实测 130–300 ms),
|
|
42
|
+
# 而指纹盖不住的那点排序漂移在一小时内不构成路由错误,放宽到 1 h。
|
|
43
|
+
_ROUTE_CACHE_TTL_S = 3600.0
|
|
44
|
+
_ROUTE_CACHE_MAX_ENTRIES = 200
|
|
45
|
+
# 体积帽:条数帽管不住单条大小(engines_fallback 大清单的 decision 可达数十 KB),
|
|
46
|
+
# 200 条 × 大条目能把缓存文件顶到无界。超限从最旧丢到帽内。
|
|
47
|
+
_ROUTE_CACHE_MAX_BYTES = 409_600
|
|
48
|
+
|
|
49
|
+
# _route_cache_read 的进程内解析缓存:(mtime_ns, size) -> entries。None = 未缓存。
|
|
50
|
+
# 声明在此而非函数内,是为了让「这个模块有一个可变全局」这件事在阅读时可见。
|
|
51
|
+
_READ_MEMO: tuple[tuple[int, int], dict[str, Any]] | None = None
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _route_cache_enabled() -> bool:
|
|
55
|
+
"""ARGO_ROUTE_CACHE=0/false/no/off 关闭;判定链不可用时按「开」处理。
|
|
56
|
+
|
|
57
|
+
缓存是纯性能优化,关掉不影响正确性;判不开时维持既有行为(每次都实算)。
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
from engine_env import env_flag
|
|
61
|
+
return env_flag("ARGO_ROUTE_CACHE", default=True)
|
|
62
|
+
except Exception:
|
|
63
|
+
return True
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _route_cache_file():
|
|
67
|
+
import argo_paths
|
|
68
|
+
return argo_paths.state_path("route-cache.json")
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _route_state_fingerprint() -> str:
|
|
72
|
+
"""影响路由决策的可变状态摘要;取不到就返回空串(等价于不用缓存)。
|
|
73
|
+
|
|
74
|
+
- `config_stamp()`:config.yaml 与外置声明的 mtime,覆盖 enabled / domains /
|
|
75
|
+
engines_combo 的改动。
|
|
76
|
+
- 配额与熔断取**派生集合**(已耗尽额度 / 已自动禁用),不取状态文件的字节或
|
|
77
|
+
mtime。为什么:`quota.json` 每次运行都会被状态机重写(mtime 必变),文件里的
|
|
78
|
+
用量计数也随每次搜索变动——**实测拿 mtime 做摘要会让缓存 100% 失效**
|
|
79
|
+
(第二次调用就换了键);而真正改变路由结果的只是「哪些源现在不可用」这个
|
|
80
|
+
集合,它只在源真的挂掉或恢复时变化。
|
|
81
|
+
|
|
82
|
+
刻意**不含** adaptive.db:自适应学习器每次搜索都写它,同理会让缓存立即失效;
|
|
83
|
+
它只影响引擎排序的软信号、变化渐进,由 TTL 兜住。
|
|
84
|
+
|
|
85
|
+
这是**粗粒度**信号:覆盖「源挂了 / 被禁」这类持久状态,瞬时节流
|
|
86
|
+
(rpm 抖动)不在其中,由 TTL 兜住。空串判据与 config 磁盘缓存 digest 取不到
|
|
87
|
+
时的保守选择一致:空摘要永不等于任何已存条目的键,因此不会读到旧结论。
|
|
88
|
+
|
|
89
|
+
刻意**不含** quota marks:额度耗尽是 per-engine 信号,已在 _get_engines_combo
|
|
90
|
+
和 _run_one 层面检查;放进指纹会让单个引擎额度变化使所有查询的路由缓存
|
|
91
|
+
失效——实测这是路由缓存命中率最大的敌人。
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
from config import config_stamp
|
|
95
|
+
parts = [f"cfg={config_stamp():.0f}"]
|
|
96
|
+
except Exception:
|
|
97
|
+
return ""
|
|
98
|
+
try:
|
|
99
|
+
from circuit_breaker import get_breaker
|
|
100
|
+
parts.append("cb=" + ",".join(sorted(get_breaker().auto_disabled())))
|
|
101
|
+
except Exception:
|
|
102
|
+
return ""
|
|
103
|
+
return "|".join(parts)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _route_cache_key(query: str, engine_override: str, mode: str, depth: str,
|
|
107
|
+
context: str, engines_boost: list[str] | None,
|
|
108
|
+
fingerprint: str) -> str:
|
|
109
|
+
import hashlib
|
|
110
|
+
import json
|
|
111
|
+
raw = json.dumps({
|
|
112
|
+
"v": _ROUTE_CACHE_SCHEMA,
|
|
113
|
+
# 归一化空白:同一问题多打几个空格不该是两次路由
|
|
114
|
+
"q": " ".join(str(query or "").split()),
|
|
115
|
+
"eo": engine_override or "auto",
|
|
116
|
+
"mode": mode, "depth": depth, "context": context,
|
|
117
|
+
"boost": [str(b) for b in (engines_boost or [])],
|
|
118
|
+
"fp": fingerprint,
|
|
119
|
+
}, ensure_ascii=False, sort_keys=True)
|
|
120
|
+
return hashlib.sha256(raw.encode("utf-8")).hexdigest()[:32]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _extract_entries(payload: Any) -> dict[str, Any]:
|
|
124
|
+
if not isinstance(payload, dict) or payload.get("schema") != _ROUTE_CACHE_SCHEMA:
|
|
125
|
+
return {}
|
|
126
|
+
entries = payload.get("entries")
|
|
127
|
+
return entries if isinstance(entries, dict) else {}
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _route_cache_read() -> dict[str, Any]:
|
|
131
|
+
import json
|
|
132
|
+
# 进程内 memo:一次 argo 调用里 _route_cache_read 可能被调多次,而每次都
|
|
133
|
+
# 全量重解析整份 JSON(实测 24 条目 ≈ 0.4 ms,条目满 200 条时线性放大)。
|
|
134
|
+
# 以 mtime_ns + size 为失效键——写路径走 os.replace 原子替换(换 inode、
|
|
135
|
+
# 换 mtime),所以不会读到半写状态;跨进程则由 mtime 变化自然穿透。
|
|
136
|
+
global _READ_MEMO
|
|
137
|
+
f = _route_cache_file()
|
|
138
|
+
try:
|
|
139
|
+
st = f.stat()
|
|
140
|
+
except OSError:
|
|
141
|
+
_READ_MEMO = None
|
|
142
|
+
return {}
|
|
143
|
+
stamp = (st.st_mtime_ns, st.st_size)
|
|
144
|
+
if _READ_MEMO is not None and _READ_MEMO[0] == stamp:
|
|
145
|
+
return _READ_MEMO[1]
|
|
146
|
+
try:
|
|
147
|
+
entries = _extract_entries(json.loads(f.read_text(encoding="utf-8")))
|
|
148
|
+
except (OSError, ValueError):
|
|
149
|
+
return {}
|
|
150
|
+
_READ_MEMO = (stamp, entries)
|
|
151
|
+
return entries
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _route_cache_prune(entries: dict[str, Any]) -> dict[str, Any]:
|
|
155
|
+
now = time.time()
|
|
156
|
+
fresh = {k: v for k, v in entries.items()
|
|
157
|
+
if isinstance(v, dict)
|
|
158
|
+
and now - float(v.get("ts") or 0) <= _ROUTE_CACHE_TTL_S}
|
|
159
|
+
if len(fresh) > _ROUTE_CACHE_MAX_ENTRIES:
|
|
160
|
+
newest = sorted(fresh.items(),
|
|
161
|
+
key=lambda kv: float(kv[1].get("ts") or 0), reverse=True)
|
|
162
|
+
fresh = dict(newest[:_ROUTE_CACHE_MAX_ENTRIES])
|
|
163
|
+
# 体积帽:从最旧开始丢,直到序列化体积进帽(条数帽管不住单条大小)
|
|
164
|
+
try:
|
|
165
|
+
import json
|
|
166
|
+
while fresh and len(json.dumps(
|
|
167
|
+
{"entries": fresh}, ensure_ascii=False).encode("utf-8")
|
|
168
|
+
) > _ROUTE_CACHE_MAX_BYTES:
|
|
169
|
+
oldest = min(fresh, key=lambda k: float(fresh[k].get("ts") or 0))
|
|
170
|
+
fresh.pop(oldest, None)
|
|
171
|
+
except (TypeError, ValueError):
|
|
172
|
+
pass
|
|
173
|
+
return fresh
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def _route_cache_write(entries: dict[str, Any]) -> None:
|
|
177
|
+
import argo_paths
|
|
178
|
+
global _READ_MEMO
|
|
179
|
+
try:
|
|
180
|
+
argo_paths.atomic_write_json(
|
|
181
|
+
_route_cache_file(),
|
|
182
|
+
{"schema": _ROUTE_CACHE_SCHEMA, "entries": entries},
|
|
183
|
+
indent=None,
|
|
184
|
+
)
|
|
185
|
+
# mtime_ns 理论上会穿透 memo,但同秒内两次写入的 mtime 粒度差异
|
|
186
|
+
# 在部分文件系统上不足 1ms。显式作废是零成本的那道保险。
|
|
187
|
+
_READ_MEMO = None
|
|
188
|
+
except Exception:
|
|
189
|
+
return
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _current_exhausted_set() -> set[str]:
|
|
193
|
+
try:
|
|
194
|
+
import quota
|
|
195
|
+
return set(quota.get_quota_manager().remote_exhausted_marks())
|
|
196
|
+
except Exception:
|
|
197
|
+
return set()
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _route_cache_entry_valid(hit: Any, ttl_s: float = _ROUTE_CACHE_TTL_S) -> bool:
|
|
201
|
+
"""缓存条目是否有效:未超 TTL、且缓存 combo 不含新耗尽引擎、且无曾耗尽引擎已恢复。"""
|
|
202
|
+
if not (isinstance(hit, dict) and isinstance(hit.get("decision"), dict)):
|
|
203
|
+
return False
|
|
204
|
+
if time.time() - float(hit.get("ts") or 0) > ttl_s:
|
|
205
|
+
return False
|
|
206
|
+
cur_rex = _current_exhausted_set()
|
|
207
|
+
combo = set(hit["decision"].get("engines_combo") or ())
|
|
208
|
+
old_rex = set(hit.get("rex") or ())
|
|
209
|
+
return not (combo & cur_rex) and not (old_rex - cur_rex)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _route_cache_pack_entry(decision: dict[str, Any]) -> dict[str, Any]:
|
|
213
|
+
return {"ts": time.time(), "decision": decision,
|
|
214
|
+
"rex": sorted(_current_exhausted_set())}
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def invalidate_route_cache() -> bool:
|
|
218
|
+
"""删除磁盘上的路由决策缓存(测试隔离与显式失效用)。"""
|
|
219
|
+
global _READ_MEMO
|
|
220
|
+
_READ_MEMO = None
|
|
221
|
+
try:
|
|
222
|
+
_route_cache_file().unlink()
|
|
223
|
+
return True
|
|
224
|
+
except OSError:
|
|
225
|
+
return False
|