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,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* diagnostics.js — argo-dsh 运行时监控与连接池只读诊断
|
|
3
|
+
*
|
|
4
|
+
* 为设置面板、外部插件或排查脚本提供只读状态自省能力,
|
|
5
|
+
* 避免状态探查逻辑与核心检索逻辑耦合。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 获取当前常驻 MCP 连接池的运行时指标。
|
|
10
|
+
*
|
|
11
|
+
* @param {Array} pool - MCP 连接池实例数组
|
|
12
|
+
* @returns {Object} 包含连接数、当前负载以及各连接健康状态的快照
|
|
13
|
+
*/
|
|
14
|
+
export function getMcpPoolStats(pool = []) {
|
|
15
|
+
const connections = pool.map((conn, index) => ({
|
|
16
|
+
index,
|
|
17
|
+
load: typeof conn.load === 'function' ? conn.load() : 0,
|
|
18
|
+
hasProcess: Boolean(conn.proc ?? true),
|
|
19
|
+
}))
|
|
20
|
+
|
|
21
|
+
const totalLoad = connections.reduce((sum, item) => sum + item.load, 0)
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
poolSize: pool.length,
|
|
25
|
+
activeConnections: pool.filter(conn => typeof conn.load === 'function' && conn.load() > 0).length,
|
|
26
|
+
totalLoad,
|
|
27
|
+
connections,
|
|
28
|
+
timestamp: Date.now(),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* 诊断并重置 MCP 连接池。
|
|
34
|
+
*
|
|
35
|
+
* @param {Array} pool - MCP 连接池实例数组
|
|
36
|
+
* @param {Function} disposeFn - 释放函数
|
|
37
|
+
* @returns {Object} 重置结果摘要
|
|
38
|
+
*/
|
|
39
|
+
export function resetMcpPool(pool = [], disposeFn) {
|
|
40
|
+
const beforeCount = pool.length
|
|
41
|
+
if (typeof disposeFn === 'function') {
|
|
42
|
+
disposeFn()
|
|
43
|
+
} else {
|
|
44
|
+
for (const conn of [...pool]) {
|
|
45
|
+
try { conn.close?.() } catch { /* ignore */ }
|
|
46
|
+
}
|
|
47
|
+
pool.length = 0
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
evictedCount: beforeCount,
|
|
51
|
+
poolSizeNow: pool.length,
|
|
52
|
+
success: true,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,527 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @taxueseek/argo-dsh — wide_research + argo 原生工具 + 原生 web_search provider
|
|
3
|
+
*
|
|
4
|
+
* 本 bundle 默认不挂 argo MCP:搜索/抓取高频路径走原生工具与 web seam
|
|
5
|
+
* (CLI 单发,同引擎同守卫,零常驻 token 开销);MCP 19 工具全量面按需
|
|
6
|
+
* 在 profile patch 中挂载。Workers 不调用 argo_research,避免嵌套扇出。
|
|
7
|
+
* 只依赖公开服务 ctx.tools / ctx.subagents / ctx.web / ctx.settings;唯一
|
|
8
|
+
* 的 @deepseek-ai/* 引用是可选的 schemastery(设置表单 schema,导入失败
|
|
9
|
+
* 时插件照常加载,只是没有设置页)。
|
|
10
|
+
*
|
|
11
|
+
* 三形态接入(互为冗余,同一搜索能力,按宿主能力自动降级):
|
|
12
|
+
* 1. mcp__argo__*:profile 按需挂载的 stdio MCP,完整工具面(默认关)
|
|
13
|
+
* 2. 原生一等工具 argo_search / argo_fetch(ctx.tools.register):CLI 单发
|
|
14
|
+
* 执行(bin call / mcp_server.py --call),不依赖 MCP 连接,默认入口;
|
|
15
|
+
* nativeTools 配置(空数组=关)
|
|
16
|
+
* 3. 原生 web_search seam:web.registerSearchProvider 注册 "argo"
|
|
17
|
+
* provider,内置 web_search 经 argo 引擎链路由;默认启用
|
|
18
|
+
* (searchProviderEnabled: false 时注册但不可选)
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFileSync } from 'node:fs'
|
|
22
|
+
import { dirname, join } from 'node:path'
|
|
23
|
+
import { fileURLToPath } from 'node:url'
|
|
24
|
+
import { NATIVE_TOOLS as NATIVE_TOOL_SPECS } from './native-tools.mjs'
|
|
25
|
+
|
|
26
|
+
import {
|
|
27
|
+
DEFAULTS,
|
|
28
|
+
PLUGIN_VERSION as RUNNER_PLUGIN_VERSION,
|
|
29
|
+
setEnvResolver,
|
|
30
|
+
resolveEntry,
|
|
31
|
+
resolveNativeSpawn,
|
|
32
|
+
makeNativeTool,
|
|
33
|
+
nativeViaMcpPool,
|
|
34
|
+
runNativeCall,
|
|
35
|
+
disposeSharedMcp,
|
|
36
|
+
searchViaArgoMCP,
|
|
37
|
+
fetchViaArgo,
|
|
38
|
+
mapArgoToWebResult,
|
|
39
|
+
mapArgoToWebFetch,
|
|
40
|
+
classifyFetchError,
|
|
41
|
+
argoAborted,
|
|
42
|
+
argoToolError,
|
|
43
|
+
} from './runner.js'
|
|
44
|
+
|
|
45
|
+
import {
|
|
46
|
+
normalizeTracks,
|
|
47
|
+
stageTracks,
|
|
48
|
+
evaluateGates,
|
|
49
|
+
normalizeSource,
|
|
50
|
+
normalizeSourceUrl,
|
|
51
|
+
buildLocalSources,
|
|
52
|
+
parseJsonArray,
|
|
53
|
+
parseJsonObject,
|
|
54
|
+
extractValues,
|
|
55
|
+
persistReport,
|
|
56
|
+
startStructured,
|
|
57
|
+
providerSupportsStructured,
|
|
58
|
+
recomputeViaArgoMCP,
|
|
59
|
+
createWideResearchTool,
|
|
60
|
+
} from './wide-research.js'
|
|
61
|
+
|
|
62
|
+
import {
|
|
63
|
+
getMcpPoolStats,
|
|
64
|
+
resetMcpPool,
|
|
65
|
+
} from './diagnostics.js'
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Schemastery 是可选依赖:装进 DSH profile 后由宿主依赖树提供,仓内单测
|
|
69
|
+
* 没有 node_modules。导入失败时 Config 保持 undefined,宿主按「无 schema」
|
|
70
|
+
* 处理——插件其余功能照常,只是设置页不会出现。不为了一个设置表单把
|
|
71
|
+
* 插件变成不可加载。
|
|
72
|
+
*/
|
|
73
|
+
let Schema
|
|
74
|
+
try {
|
|
75
|
+
const schemastery = await import('@deepseek-ai/schemastery')
|
|
76
|
+
Schema = schemastery.default ?? schemastery.Schema ?? schemastery
|
|
77
|
+
} catch {
|
|
78
|
+
Schema = undefined
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 本插件版本:从自己的 package.json 读,**不写死字面量**。
|
|
83
|
+
*/
|
|
84
|
+
function resolvePluginVersion() {
|
|
85
|
+
try {
|
|
86
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
87
|
+
const raw = readFileSync(join(here, '..', 'package.json'), 'utf8')
|
|
88
|
+
const parsed = JSON.parse(raw)
|
|
89
|
+
if (typeof parsed?.version === 'string' && parsed.version !== '') return parsed.version
|
|
90
|
+
} catch { /* 打包裁剪/权限异常:回退,不阻断插件加载 */ }
|
|
91
|
+
return RUNNER_PLUGIN_VERSION || '0.0.0-unknown'
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export const PLUGIN_VERSION = resolvePluginVersion()
|
|
95
|
+
|
|
96
|
+
export const name = 'wide-research'
|
|
97
|
+
export const inject = ['tools', 'subagents', 'systemPrompt']
|
|
98
|
+
|
|
99
|
+
const MCP_CHILD_TOOLS = Object.keys(NATIVE_TOOL_SPECS).map(name => `mcp__argo__${name}`)
|
|
100
|
+
const DEFAULT_CHILD_TOOLS = Object.freeze([
|
|
101
|
+
...MCP_CHILD_TOOLS,
|
|
102
|
+
'argo_search',
|
|
103
|
+
'argo_fetch',
|
|
104
|
+
'web_search',
|
|
105
|
+
'web_fetch',
|
|
106
|
+
])
|
|
107
|
+
|
|
108
|
+
export function buildChildToolFilters(config, toolName) {
|
|
109
|
+
const base = Array.isArray(config?.childToolAllow) ? config.childToolAllow : DEFAULT_CHILD_TOOLS
|
|
110
|
+
const blocked = new Set([toolName, 'mcp__argo__argo_research'])
|
|
111
|
+
const deny = [...new Set([toolName, ...asStringArray(config?.childToolDeny, 100)])]
|
|
112
|
+
const denySet = new Set(deny)
|
|
113
|
+
const allow = [...new Set(asStringArray(base, 100).filter(tool => !blocked.has(tool) && !denySet.has(tool)))]
|
|
114
|
+
return { allow, deny }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 面板可露出的 argo 环境变量开关(curated 白名单)。
|
|
119
|
+
*
|
|
120
|
+
* 选录标准:日常会开合的行为开关,语义单一、默认值在 argo 侧稳定;授权位
|
|
121
|
+
* (ARGO_ALLOW_RECOMPUTE / ARGO_ALLOW_PRIVATE_URLS,argo 要求 expand=False
|
|
122
|
+
* + strict=True)与路径/状态类内部变量(ARGO_STATE_DIR / ARGO_HOME /
|
|
123
|
+
* ARGO_DAEMON 等)刻意不收——前者不该一键放行,后者改了会动摇凭证 seam 的
|
|
124
|
+
* 解析前提。每个名字都在 argo 仓 scripts/ 有读取点,由
|
|
125
|
+
* tests/test_dsh_plugin_env_gate.py 对拍,防白名单漂移成 Fiction。
|
|
126
|
+
*
|
|
127
|
+
* kind:bool=开关(值 0/1)、num=数字,str=字符串,list=名单(逗号或路径分隔符分隔,照 argo 原语义)。
|
|
128
|
+
* def=argo 侧默认值(仅面板展示用,缺省即不写该行、由 argo 自己决定)。
|
|
129
|
+
*
|
|
130
|
+
* 开关文案一律写「正向行为」或「明确的关闭动作」,**不要再用 invert 反转**:
|
|
131
|
+
* 历史 bug(2026-10-22)——`关闭搜索结果缓存` 配 invert 后,未配置时面板显示
|
|
132
|
+
* 为「开」,点一下反而把 ARGO_NO_CACHE 写成 0,缓存始终没关掉。
|
|
133
|
+
*/
|
|
134
|
+
export const ARGO_ENV_SPECS = Object.freeze([
|
|
135
|
+
{ name: 'ARGO_NO_CACHE', kind: 'bool', group: 'cache', def: false, zh: '测试模式(关闭结果缓存)', en: 'Test mode (disable result cache)', hintZh: '日常保持关闭:结果缓存 1 小时。改进 Skill/插件、需要看实时结果时再打开', hintEn: 'Off by default: results are cached for 1h. Enable only when developing the skill/plugin' },
|
|
136
|
+
{ name: 'ARGO_TFIDF_RERANK', kind: 'bool', group: 'cache', def: true, zh: 'TF-IDF 重排', en: 'TF-IDF rerank', hintZh: '多引擎结果融合前的相关性重排,默认开', hintEn: 'Relevance rerank before fusion, on by default' },
|
|
137
|
+
{ name: 'ARGO_NUMBER_CROSSCHECK', kind: 'bool', group: 'cache', def: true, zh: '数值交叉校验', en: 'Number cross-check', hintZh: '对查询里的数值主张做跨源核对,默认开', hintEn: 'Cross-check numeric claims across sources, on by default' },
|
|
138
|
+
{ name: 'ARGO_MINHASH_DEDUPE', kind: 'bool', group: 'cache', def: true, zh: 'MinHash 去重', en: 'MinHash dedupe', hintZh: '近重复结果合并,默认开', hintEn: 'Merge near-duplicate results, on by default' },
|
|
139
|
+
{ name: 'ARGO_MINHASH_THRESHOLD', kind: 'num', group: 'cache', def: 0.85, min: 0.5, max: 1, step: 0.05, zh: '去重阈值', en: 'Dedupe threshold', hintZh: '越高越严(越多判为不同),默认 0.85', hintEn: 'Higher = stricter, default 0.85' },
|
|
140
|
+
{ name: 'ARGO_SERP_GUARD', kind: 'bool', group: 'cache', def: true, zh: 'SERP 守卫', en: 'SERP guard', hintZh: '拦截壳页/风控页混入结果,默认开;误杀时先关它复现', hintEn: 'Keep shell/blocked pages out of results, on by default' },
|
|
141
|
+
{ name: 'ARGO_FETCH_JINA', kind: 'bool', group: 'fetch', def: true, zh: 'Jina 阅读器抓取', en: 'Jina reader fetch', hintZh: 'r.jina.ai 正文提取,默认开', hintEn: 'r.jina.ai text extraction, on by default' },
|
|
142
|
+
{ name: 'ARGO_FETCH_MOBILE', kind: 'bool', group: 'fetch', def: true, zh: '移动端 UA 抓取', en: 'Mobile UA fetch', hintZh: '按 host 记忆移动端身份,默认开', hintEn: 'Per-host mobile identity, on by default' },
|
|
143
|
+
{ name: 'ARGO_FETCH_PARALLEL', kind: 'bool', group: 'fetch', def: true, zh: 'Parallel 免费渲染抓取', en: 'Parallel free render fetch', hintZh: 'keyless 云端渲染兜底,默认开', hintEn: 'Keyless cloud render fallback, on by default' },
|
|
144
|
+
{ name: 'ARGO_FETCH_DEADLINE_S', kind: 'num', group: 'fetch', def: 60, min: 5, max: 300, step: 5, zh: '抓取总截止(秒)', en: 'Fetch deadline (s)', hintZh: '单次抓取全链路墙钟上限,默认 60', hintEn: 'Wall-clock cap per fetch, default 60' },
|
|
145
|
+
{ name: 'ARGO_SEMANTIC_EVIDENCE', kind: 'bool', group: 'semantic', def: false, zh: '语义证据层', en: 'Semantic evidence', hintZh: '显式核验链路的零样本判定,默认关;开启后多一次外呼', hintEn: 'Zero-shot support check on the verify path, off by default' },
|
|
146
|
+
{ name: 'ARGO_ADAPTIVE_GRACE', kind: 'bool', group: 'semantic', def: true, zh: '对冲宽限自适应', en: 'Adaptive hedge grace', hintZh: '按引擎历史 p75 收窄对冲等待窗,默认开', hintEn: 'Narrow hedge window by engine p75, on by default' },
|
|
147
|
+
{ name: 'ARGO_ADAPTIVE_TAIL', kind: 'bool', group: 'semantic', def: false, zh: '分层尾宽', en: 'Layered straggler tail', hintZh: '尾宽按未回来引擎分层取值,默认关', hintEn: 'Per-engine layered tail width, off by default' },
|
|
148
|
+
{ name: 'ARGO_STRAGGLER_GRACE_S', kind: 'num', group: 'semantic', def: 1.5, min: 0, max: 30, step: 0.5, zh: '掉队宽限(秒)', en: 'Straggler grace (s)', hintZh: '已有引擎交付后还等多久,默认 1.5;0 关闭', hintEn: 'Wait after first delivery, default 1.5; 0 disables' },
|
|
149
|
+
{ name: 'ARGO_SERIAL_STAGGER_S', kind: 'num', group: 'semantic', def: 0.8, min: 0, max: 30, step: 0.5, zh: '串行起步间隔(秒)', en: 'Serial stagger (s)', hintZh: '首引擎超时前补发备选源的提前量,默认 0.8;0 最激进', hintEn: 'Lead before firing a backup source, default 0.8; 0 = fire together' },
|
|
150
|
+
{ name: 'ARGO_ENABLE_ENGINES', kind: 'list', group: 'engines', zh: '额外启用引擎', en: 'Extra enabled engines', hintZh: '逗号分隔;叠加在 config.yaml 启用集之上', hintEn: 'Comma-separated; adds to the config.yaml enabled set' },
|
|
151
|
+
{ name: 'ARGO_DISABLE_ENGINES', kind: 'list', group: 'engines', zh: '停用引擎', en: 'Disabled engines', hintZh: '逗号分隔;优先级高于启用集,调试单引擎时用', hintEn: 'Comma-separated; wins over the enabled set' },
|
|
152
|
+
{ name: 'ARGO_PROXY', kind: 'str', group: 'net', zh: 'argo 全局代理', en: 'argo global proxy', hintZh: 'http:// 代理 URL,或 direct 强制直连;留空走环境变量', hintEn: 'http:// proxy URL, or direct; empty falls back to env' },
|
|
153
|
+
{ name: 'ARGO_GDELT_PROXY', kind: 'str', group: 'net', zh: 'GDELT 代理', en: 'GDELT proxy', hintZh: 'GDELT 按出口 IP 限流,经本地代理更稳;留空自动直连', hintEn: 'GDELT rate-limits by egress IP; empty = direct' },
|
|
154
|
+
{ name: 'ARGO_LOCAL_SEEK_ROOTS', kind: 'list', group: 'local', zh: '本机检索根目录', en: 'Local seek roots', hintZh: '路径分隔符分隔;seek.py 的候选安装根,默认用打包位置', hintEn: 'Path-separated roots for seek.py; default uses the bundled copy' },
|
|
155
|
+
{ name: 'ARGO_LOCAL_SEEK_PATH', kind: 'str', group: 'local', zh: 'seek.py 绝对路径', en: 'seek.py path', hintZh: '显式指定 seek.py,优先于根目录候选', hintEn: 'Explicit seek.py, wins over root candidates' },
|
|
156
|
+
{ name: 'ARGO_LOCAL_READ_DIRS', kind: 'list', group: 'local', zh: '本机读取白名单', en: 'Local read allowlist', hintZh: '逗号分隔;不配置则 local_read 一律不放行', hintEn: 'Comma-separated; empty means local_read allows nothing' },
|
|
157
|
+
{ name: 'ARGO_TEXT_LEXICON', kind: 'str', group: 'local', zh: '词表 JSON 路径', en: 'Lexicon JSON path', hintZh: '文本处理词表覆盖,默认用打包词表', hintEn: 'Text lexicon override; default uses the bundled one' },
|
|
158
|
+
{ name: 'ARGO_PAID_SEARCH', kind: 'str', group: 'paid', def: 'auto', zh: '付费源策略', en: 'Paid source policy', hintZh: 'auto=优势域自动使用付费源;off=只用免费源。额度见下方', hintEn: 'auto = use paid sources in proven domains; off = free sources only. See quotas below' },
|
|
159
|
+
{ name: 'ARGO_BUDGET_DEEPSEEK_SEARCH', kind: 'num', group: 'paid', def: 5, min: 0, max: 1000, step: 1, zh: 'DeepSeek 月度预算(元)', en: 'DeepSeek monthly budget (CNY)', hintZh: '0=关闭;¥5≈1000次成功调用(¥0.005/次)', hintEn: '0 = off; CNY 5 ≈ 1000 successful calls (CNY 0.005 each)' },
|
|
160
|
+
{ name: 'ARGO_BUDGET_EXA', kind: 'num', group: 'paid', def: 10, min: 0, max: 10000, step: 1, zh: 'Exa 每月预算(美元)', en: 'Exa monthly budget (USD)', hintZh: '默认 $10/月(约 1000 次);0=关闭自动使用。按成功调用计费', hintEn: 'Default $10/month (~1000 calls); 0 = off. Billed per successful call' },
|
|
161
|
+
{ name: 'ARGO_QUOTA_ANYSEARCH_LIMIT', kind: 'num', group: 'paid', def: 1000, min: 0, max: 1000000, step: 1, zh: 'AnySearch 每日次数上限', en: 'AnySearch daily call cap', hintZh: '默认 1000/日;0=不限制。改动对下一次新建连接生效', hintEn: 'Default 1000/day; 0 = unlimited. Applies to new connections' },
|
|
162
|
+
{ name: 'ARGO_QUOTA_ZHIHU_LIMIT', kind: 'num', group: 'paid', def: 5000, min: 0, max: 1000000, step: 1, zh: '知乎 每日次数上限', en: 'Zhihu daily call cap', hintZh: '默认 5000/日;0=不限制。改动对下一次新建连接生效', hintEn: 'Default 5000/day; 0 = unlimited. Applies to new connections' },
|
|
163
|
+
{ name: 'ARGO_QUOTA_YUANBAO_LIMIT', kind: 'num', group: 'paid', def: 2000, min: 0, max: 1000000, step: 1, zh: '元宝 每月次数上限', en: 'Yuanbao monthly call cap', hintZh: '默认 2000/月;0=不限制。改动对下一次新建连接生效', hintEn: 'Default 2000/month; 0 = unlimited. Applies to new connections' },
|
|
164
|
+
{ name: 'ARGO_QUOTA_TAVILY_LIMIT', kind: 'num', group: 'paid', def: 1000, min: 0, max: 1000000, step: 1, zh: 'Tavily 每月次数上限', en: 'Tavily monthly call cap', hintZh: '默认 1000/月;0=不限制。改动对下一次新建连接生效', hintEn: 'Default 1000/month; 0 = unlimited. Applies to new connections' },
|
|
165
|
+
{ name: 'ARGO_NO_PREWARM', kind: 'bool', group: 'misc', def: false, zh: '关闭连接预热', en: 'Disable prewarm', hintZh: 'MCP 握手后预热引擎注册表,默认开;开启本项即关闭预热', hintEn: 'Prewarm the engine registry after handshake, on by default; enable this to turn it off' },
|
|
166
|
+
{ name: 'ARGO_USAGE_LOG', kind: 'bool', group: 'misc', def: true, zh: '使用日志', en: 'Usage log', hintZh: 'argo 侧 JSONL 使用账本,默认开', hintEn: 'argo JSONL usage ledger, on by default' },
|
|
167
|
+
{ name: 'ARGO_ENGINE_HTTP_CLIENT', kind: 'bool', group: 'misc', def: true, zh: 'HttpClient 连接池', en: 'HttpClient pool', hintZh: '引擎 HTTP 走连接池,默认开;=0 回退 urllib(诊断用)', hintEn: 'Pooled engine HTTP, on by default; =0 falls back to urllib' },
|
|
168
|
+
{ name: 'ARGO_ADMISSION_TTL_S', kind: 'num', group: 'misc', def: 1, min: 0, max: 60, step: 0.5, zh: '准入记忆 TTL(秒)', en: 'Admission memo TTL (s)', hintZh: '引擎准入状态记忆时长,默认 1;0 每次现查', hintEn: 'Admission memo window, default 1; 0 = always fresh' },
|
|
169
|
+
{ name: 'ARGO_CONFIG_STAMP_TTL_S', kind: 'num', group: 'misc', def: 1, min: 0, max: 60, step: 0.5, zh: '配置戳记忆 TTL(秒)', en: 'Config stamp memo TTL (s)', hintZh: '外部引擎扫描记忆时长,默认 1;0 每次现扫', hintEn: 'External engine scan memo window, default 1; 0 = always rescan' },
|
|
170
|
+
])
|
|
171
|
+
|
|
172
|
+
const ARGO_ENV_NAMES = new Set(ARGO_ENV_SPECS.map(spec => spec.name))
|
|
173
|
+
const ARGO_ENV_BY_NAME = new Map(ARGO_ENV_SPECS.map(spec => [spec.name, spec]))
|
|
174
|
+
|
|
175
|
+
function parseArgoEnvLine(line) {
|
|
176
|
+
const eq = line.indexOf('=')
|
|
177
|
+
if (eq <= 0) return null
|
|
178
|
+
const name = line.slice(0, eq).trim()
|
|
179
|
+
const value = line.slice(eq + 1)
|
|
180
|
+
if (!CREDENTIAL_REF_PATTERN.test(name)) return null
|
|
181
|
+
return { name, value }
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export function argoEnvOverlay(config = activeConfig) {
|
|
185
|
+
const overlay = {}
|
|
186
|
+
for (const entry of asStringArray(config?.argoEnv, 64)) {
|
|
187
|
+
const parsed = parseArgoEnvLine(entry)
|
|
188
|
+
if (parsed === null || !ARGO_ENV_NAMES.has(parsed.name)) continue
|
|
189
|
+
overlay[parsed.name] = parsed.value
|
|
190
|
+
}
|
|
191
|
+
return overlay
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
195
|
+
|
|
196
|
+
const VOLATILE_WRITE = Symbol.for('cosmokit.volatile.write')
|
|
197
|
+
const isVolatileRef = (value) =>
|
|
198
|
+
typeof value === 'object' && value !== null && VOLATILE_WRITE in value && typeof value.get === 'function'
|
|
199
|
+
|
|
200
|
+
function liveConfig(provided) {
|
|
201
|
+
const base = isObject(provided) ? provided : {}
|
|
202
|
+
return new Proxy(base, {
|
|
203
|
+
get(target, key) {
|
|
204
|
+
const raw = Reflect.get(target, key)
|
|
205
|
+
const value = isVolatileRef(raw) ? raw.get() : raw
|
|
206
|
+
return value !== undefined ? value : DEFAULTS[key]
|
|
207
|
+
},
|
|
208
|
+
has(target, key) {
|
|
209
|
+
return Reflect.has(target, key) || key in DEFAULTS
|
|
210
|
+
},
|
|
211
|
+
ownKeys(target) {
|
|
212
|
+
return [...new Set([...Reflect.ownKeys(target), ...Object.keys(DEFAULTS)])]
|
|
213
|
+
},
|
|
214
|
+
getOwnPropertyDescriptor(target, key) {
|
|
215
|
+
const desc = Reflect.getOwnPropertyDescriptor(target, key)
|
|
216
|
+
if (desc !== undefined) return desc
|
|
217
|
+
if (key in DEFAULTS) return { value: DEFAULTS[key], writable: true, enumerable: true, configurable: true }
|
|
218
|
+
return undefined
|
|
219
|
+
},
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const NATIVE_TOOL_NAMES = Object.keys(NATIVE_TOOL_SPECS)
|
|
224
|
+
|
|
225
|
+
export const Config = Schema === undefined ? undefined : Schema.object({
|
|
226
|
+
toolName: Schema.string().default(DEFAULTS.toolName)
|
|
227
|
+
.description('研究工具名(结构性设置,改动需重启)'),
|
|
228
|
+
provider: Schema.string().default(DEFAULTS.provider)
|
|
229
|
+
.description('wide_research 使用的子代理 provider(结构性设置,改动需重启)'),
|
|
230
|
+
searchProviderId: Schema.string().default(DEFAULTS.searchProviderId)
|
|
231
|
+
.description('web_search provider id(结构性设置;改动需同步 web 行 searchProvider)'),
|
|
232
|
+
fetchProviderId: Schema.string().default(DEFAULTS.fetchProviderId)
|
|
233
|
+
.description('web_fetch provider id(结构性设置;改动需同步 web 行 fetchProvider)'),
|
|
234
|
+
nativeTools: Schema.array(Schema.union(NATIVE_TOOL_NAMES)).default([...DEFAULTS.nativeTools])
|
|
235
|
+
.description('注册为原生一等工具的 argo 工具名;空数组关闭。默认 argo_search / argo_fetch')
|
|
236
|
+
.volatile(),
|
|
237
|
+
nativeTimeoutMs: Schema.number().default(DEFAULTS.nativeTimeoutMs)
|
|
238
|
+
.description('原生工具单次进程超时(毫秒)')
|
|
239
|
+
.volatile(),
|
|
240
|
+
nativeMaxChars: Schema.number().default(DEFAULTS.nativeMaxChars)
|
|
241
|
+
.description('原生工具返回文本上限(字符)')
|
|
242
|
+
.volatile(),
|
|
243
|
+
searchProviderEnabled: Schema.boolean().default(DEFAULTS.searchProviderEnabled)
|
|
244
|
+
.description('宿主 web_search 走 argo provider')
|
|
245
|
+
.volatile(),
|
|
246
|
+
fetchProviderEnabled: Schema.boolean().default(DEFAULTS.fetchProviderEnabled)
|
|
247
|
+
.description('宿主 web_fetch 走 argo provider(启用需在 web 行 pin fetchProvider: argo)')
|
|
248
|
+
.volatile(),
|
|
249
|
+
searchCommand: Schema.string().default(DEFAULTS.searchCommand)
|
|
250
|
+
.description('argo MCP 入口命令(npx 或本机 python3)')
|
|
251
|
+
.volatile(),
|
|
252
|
+
searchArgs: Schema.array(Schema.string()).default([...DEFAULTS.searchArgs])
|
|
253
|
+
.description('argo MCP 入口参数,一行一个')
|
|
254
|
+
.volatile(),
|
|
255
|
+
searchTimeoutMs: Schema.number().default(DEFAULTS.searchTimeoutMs)
|
|
256
|
+
.description('单次搜索超时(毫秒)')
|
|
257
|
+
.volatile(),
|
|
258
|
+
searchIdleMs: Schema.number().default(DEFAULTS.searchIdleMs)
|
|
259
|
+
.description('常驻 MCP 连接空闲回收(毫秒,0=不回收)')
|
|
260
|
+
.volatile(),
|
|
261
|
+
searchConcurrency: Schema.number().default(DEFAULTS.searchConcurrency)
|
|
262
|
+
.description('MCP 连接池上限(并发搜索度)')
|
|
263
|
+
.volatile(),
|
|
264
|
+
fetchTimeoutMs: Schema.number().default(DEFAULTS.fetchTimeoutMs)
|
|
265
|
+
.description('web_fetch seam 单次预算(毫秒)')
|
|
266
|
+
.volatile(),
|
|
267
|
+
fetchMaxChars: Schema.number().default(DEFAULTS.fetchMaxChars)
|
|
268
|
+
.description('web_fetch seam 正文上限(字符)')
|
|
269
|
+
.volatile(),
|
|
270
|
+
defaultWorkers: Schema.number().default(DEFAULTS.defaultWorkers)
|
|
271
|
+
.description('wide_research 默认并发 worker 数')
|
|
272
|
+
.volatile(),
|
|
273
|
+
maxWorkers: Schema.number().default(DEFAULTS.maxWorkers)
|
|
274
|
+
.description('wide_research 并发 worker 上限')
|
|
275
|
+
.volatile(),
|
|
276
|
+
maxTracks: Schema.number().default(DEFAULTS.maxTracks)
|
|
277
|
+
.description('wide_research 研究轨道上限')
|
|
278
|
+
.volatile(),
|
|
279
|
+
maxSourcesPerTrack: Schema.number().default(DEFAULTS.maxSourcesPerTrack)
|
|
280
|
+
.description('每条轨道最多保留的信源数')
|
|
281
|
+
.volatile(),
|
|
282
|
+
workerMaxTokens: Schema.number().default(DEFAULTS.workerMaxTokens)
|
|
283
|
+
.description('单个 worker 的输出 token 上限')
|
|
284
|
+
.volatile(),
|
|
285
|
+
synthesisMaxTokens: Schema.number().default(DEFAULTS.synthesisMaxTokens)
|
|
286
|
+
.description('综合阶段输出 token 上限')
|
|
287
|
+
.volatile(),
|
|
288
|
+
reportDir: Schema.string().default(DEFAULTS.reportDir)
|
|
289
|
+
.description('研究报告落盘目录')
|
|
290
|
+
.volatile(),
|
|
291
|
+
childToolAllow: Schema.array(Schema.string()).default([...DEFAULT_CHILD_TOOLS])
|
|
292
|
+
.description('worker 可见工具白名单(allow 语义)')
|
|
293
|
+
.volatile(),
|
|
294
|
+
childToolDeny: Schema.array(Schema.string()).default([...DEFAULTS.childToolDeny])
|
|
295
|
+
.description('worker 工具拒绝名单')
|
|
296
|
+
.volatile(),
|
|
297
|
+
keyRefs: Schema.array(Schema.string()).default([...DEFAULTS.keyRefs])
|
|
298
|
+
.description('转发进 argo 子进程的宿主凭证引用名(环境变量名)')
|
|
299
|
+
.volatile(),
|
|
300
|
+
argoEnv: Schema.array(Schema.string()).default([...DEFAULTS.argoEnv])
|
|
301
|
+
.description('argo 引擎开关(一行一个 KEY=VALUE,名字限 ARGO_ENV_SPECS 白名单)')
|
|
302
|
+
.volatile(),
|
|
303
|
+
})
|
|
304
|
+
|
|
305
|
+
const CREDENTIAL_REF_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/
|
|
306
|
+
|
|
307
|
+
function readHostCredentials(ctx) {
|
|
308
|
+
try {
|
|
309
|
+
const service = typeof ctx?.get === 'function' ? ctx.get('credentials') : ctx?.credentials
|
|
310
|
+
return service !== undefined && service !== null && typeof service.resolve === 'function'
|
|
311
|
+
? service
|
|
312
|
+
: undefined
|
|
313
|
+
} catch {
|
|
314
|
+
return undefined
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function runEffect(ctx, fn) {
|
|
319
|
+
if (typeof ctx?.effect !== 'function') return undefined
|
|
320
|
+
return ctx.effect(fn)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
let hostCredentials = undefined
|
|
324
|
+
let activeConfig = DEFAULTS
|
|
325
|
+
|
|
326
|
+
export async function resolveArgoEnv(config = activeConfig, options = {}) {
|
|
327
|
+
const overlay = argoEnvOverlay(config)
|
|
328
|
+
const refs = asStringArray(config?.keyRefs, 20)
|
|
329
|
+
if (refs.length > 0) {
|
|
330
|
+
const provider = options.credentials ?? config?.credentials ?? hostCredentials
|
|
331
|
+
if (provider !== undefined) {
|
|
332
|
+
for (const ref of refs) {
|
|
333
|
+
try {
|
|
334
|
+
const resolved = await provider.resolve(ref)
|
|
335
|
+
if (typeof resolved?.value === 'string' && resolved.value !== '') overlay[ref] = resolved.value
|
|
336
|
+
} catch { /* ignore */ }
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return Object.keys(overlay).length > 0 ? { ...process.env, ...overlay } : undefined
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const asString = (value, fallback = '') => typeof value === 'string' ? value.trim() : fallback
|
|
344
|
+
const asStringArray = (value, maximum) => Array.isArray(value)
|
|
345
|
+
? value.filter(entry => typeof entry === 'string').map(entry => entry.trim()).filter(Boolean).slice(0, maximum)
|
|
346
|
+
: []
|
|
347
|
+
|
|
348
|
+
// 注入执行器的动态环境变量解析逻辑
|
|
349
|
+
setEnvResolver(async (options, config) => {
|
|
350
|
+
return resolveArgoEnv(config || activeConfig, options)
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
export function apply(ctx, providedConfig = {}) {
|
|
354
|
+
const config = liveConfig(providedConfig)
|
|
355
|
+
const toolName = asString(config.toolName, DEFAULTS.toolName)
|
|
356
|
+
const providerName = asString(config.provider, DEFAULTS.provider)
|
|
357
|
+
|
|
358
|
+
const nativeTools = asStringArray(config.nativeTools, 20)
|
|
359
|
+
if (config.searchProviderEnabled !== false || nativeTools.length > 0) {
|
|
360
|
+
if (typeof config.searchCommand !== 'string' || config.searchCommand === '') {
|
|
361
|
+
throw new Error('argo-dsh: searchCommand must be a non-empty string when searchProviderEnabled')
|
|
362
|
+
}
|
|
363
|
+
if (!Array.isArray(config.searchArgs) || config.searchArgs.length === 0) {
|
|
364
|
+
throw new Error('argo-dsh: searchArgs must be a non-empty array when searchProviderEnabled')
|
|
365
|
+
}
|
|
366
|
+
if (!Number.isFinite(config.searchTimeoutMs) || config.searchTimeoutMs <= 0) {
|
|
367
|
+
throw new Error('argo-dsh: searchTimeoutMs must be a positive number')
|
|
368
|
+
}
|
|
369
|
+
if (!Number.isFinite(config.nativeTimeoutMs) || config.nativeTimeoutMs <= 0) {
|
|
370
|
+
throw new Error('argo-dsh: nativeTimeoutMs must be a positive number')
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
for (const ref of asStringArray(config.keyRefs, 20)) {
|
|
375
|
+
if (!CREDENTIAL_REF_PATTERN.test(ref)) {
|
|
376
|
+
throw new Error(`argo-dsh: keyRefs entry "${ref}" must be a POSIX-style identifier (e.g. DEEPSEEK_API_KEY)`)
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
for (const entry of asStringArray(config.argoEnv, 64)) {
|
|
381
|
+
const parsed = parseArgoEnvLine(entry)
|
|
382
|
+
if (parsed === null) {
|
|
383
|
+
throw new Error(`argo-dsh: argoEnv entry "${entry}" must be KEY=VALUE with a POSIX-style key`)
|
|
384
|
+
}
|
|
385
|
+
if (!ARGO_ENV_NAMES.has(parsed.name)) {
|
|
386
|
+
throw new Error(`argo-dsh: argoEnv key "${parsed.name}" is not a known argo switch. Known: ${[...ARGO_ENV_NAMES].join(', ')}`)
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
hostCredentials = readHostCredentials(ctx)
|
|
391
|
+
activeConfig = config
|
|
392
|
+
|
|
393
|
+
runEffect(ctx, () => () => {
|
|
394
|
+
disposeSharedMcp()
|
|
395
|
+
hostCredentials = undefined
|
|
396
|
+
activeConfig = DEFAULTS
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
const childIds = new Set()
|
|
400
|
+
const trackChild = (id) => {
|
|
401
|
+
if (typeof id !== 'string' || id === '') return () => {}
|
|
402
|
+
childIds.add(id)
|
|
403
|
+
return () => { childIds.delete(id) }
|
|
404
|
+
}
|
|
405
|
+
if (typeof ctx.tools?.guard === 'function') {
|
|
406
|
+
ctx.tools.guard((exec) => {
|
|
407
|
+
const liveToolName = asString(config.toolName, DEFAULTS.toolName)
|
|
408
|
+
if (exec?.name === liveToolName && exec?.agent && childIds.has(exec.agent.id)) {
|
|
409
|
+
return `${liveToolName} is not available inside a research worker`
|
|
410
|
+
}
|
|
411
|
+
return undefined
|
|
412
|
+
})
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const web = ctx.get?.('web') ?? ctx.web
|
|
416
|
+
if (web && typeof web.registerSearchProvider === 'function') {
|
|
417
|
+
web.registerSearchProvider({
|
|
418
|
+
id: asString(config.searchProviderId, DEFAULTS.searchProviderId),
|
|
419
|
+
available: () => config.searchProviderEnabled !== false,
|
|
420
|
+
search: (request, signal) => {
|
|
421
|
+
const entry = resolveEntry(config)
|
|
422
|
+
return searchViaArgoMCP(request.query, request.maxResults, signal, {
|
|
423
|
+
command: entry.command,
|
|
424
|
+
args: entry.args,
|
|
425
|
+
timeoutMs: config.searchTimeoutMs,
|
|
426
|
+
idleMs: config.searchIdleMs,
|
|
427
|
+
max: config.searchConcurrency,
|
|
428
|
+
config,
|
|
429
|
+
})
|
|
430
|
+
},
|
|
431
|
+
})
|
|
432
|
+
if (typeof web.registerFetchProvider === 'function') {
|
|
433
|
+
web.registerFetchProvider({
|
|
434
|
+
id: asString(config.fetchProviderId, DEFAULTS.fetchProviderId),
|
|
435
|
+
available: () => config.fetchProviderEnabled !== false,
|
|
436
|
+
fetch: (request, signal) => {
|
|
437
|
+
const entry = resolveEntry(config)
|
|
438
|
+
return fetchViaArgo(request.url, signal, {
|
|
439
|
+
command: entry.command,
|
|
440
|
+
args: entry.args,
|
|
441
|
+
timeoutMs: config.fetchTimeoutMs,
|
|
442
|
+
idleMs: config.searchIdleMs,
|
|
443
|
+
max: config.searchConcurrency,
|
|
444
|
+
maxChars: config.fetchMaxChars,
|
|
445
|
+
config,
|
|
446
|
+
})
|
|
447
|
+
},
|
|
448
|
+
})
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
const nativeRegistrations = new Map()
|
|
453
|
+
const syncNativeTools = () => {
|
|
454
|
+
const desired = asStringArray(config.nativeTools, 20)
|
|
455
|
+
for (const [kind, dispose] of nativeRegistrations) {
|
|
456
|
+
if (desired.includes(kind)) continue
|
|
457
|
+
try { dispose?.() } catch { /* ignore */ }
|
|
458
|
+
nativeRegistrations.delete(kind)
|
|
459
|
+
}
|
|
460
|
+
for (const kind of desired) {
|
|
461
|
+
if (nativeRegistrations.has(kind)) continue
|
|
462
|
+
nativeRegistrations.set(kind, ctx.tools.register(makeNativeTool(config, kind)))
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
syncNativeTools()
|
|
466
|
+
if (typeof ctx.on === 'function') {
|
|
467
|
+
runEffect(ctx, () => ctx.on('loader/volatile-update', syncNativeTools))
|
|
468
|
+
}
|
|
469
|
+
runEffect(ctx, () => () => {
|
|
470
|
+
for (const dispose of nativeRegistrations.values()) {
|
|
471
|
+
try { dispose?.() } catch { /* ignore */ }
|
|
472
|
+
}
|
|
473
|
+
nativeRegistrations.clear()
|
|
474
|
+
})
|
|
475
|
+
|
|
476
|
+
ctx.tools.register(createWideResearchTool(ctx, config, {
|
|
477
|
+
toolName,
|
|
478
|
+
providerName,
|
|
479
|
+
trackChild,
|
|
480
|
+
buildChildToolFilters,
|
|
481
|
+
}))
|
|
482
|
+
|
|
483
|
+
if (ctx.systemPrompt && typeof ctx.systemPrompt.section === 'function') {
|
|
484
|
+
ctx.systemPrompt.section({
|
|
485
|
+
name: `tool:${toolName}`,
|
|
486
|
+
order: 116.6,
|
|
487
|
+
text: () => `Use ${toolName} for broad factual research that needs independent source checks, contrasting viewpoints, or a citation-ready evidence ledger. State a bounded question and scope. Do not use it for simple answers, personal-data collection, speculative brainstorming, or irreversible actions. Treat the report as evidence synthesis, inspect key sources for high-stakes decisions, and disclose uncertainty.`,
|
|
488
|
+
})
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
try {
|
|
492
|
+
ctx.effect(() => {
|
|
493
|
+
const settings = typeof ctx.get === 'function' ? ctx.get('settings') : undefined
|
|
494
|
+
if (!settings || typeof settings.configure !== 'function') return undefined
|
|
495
|
+
return settings.configure({ auto: false }, ctx.fiber)
|
|
496
|
+
})
|
|
497
|
+
} catch { /* ignore */ }
|
|
498
|
+
|
|
499
|
+
return { childIds, syncNativeTools }
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
export {
|
|
503
|
+
normalizeTracks,
|
|
504
|
+
stageTracks,
|
|
505
|
+
evaluateGates,
|
|
506
|
+
normalizeSource,
|
|
507
|
+
normalizeSourceUrl,
|
|
508
|
+
buildLocalSources,
|
|
509
|
+
parseJsonArray,
|
|
510
|
+
parseJsonObject,
|
|
511
|
+
extractValues,
|
|
512
|
+
nativeViaMcpPool,
|
|
513
|
+
runNativeCall,
|
|
514
|
+
resolveNativeSpawn,
|
|
515
|
+
makeNativeTool,
|
|
516
|
+
disposeSharedMcp,
|
|
517
|
+
startStructured,
|
|
518
|
+
providerSupportsStructured,
|
|
519
|
+
fetchViaArgo,
|
|
520
|
+
mapArgoToWebResult,
|
|
521
|
+
mapArgoToWebFetch,
|
|
522
|
+
classifyFetchError,
|
|
523
|
+
searchViaArgoMCP,
|
|
524
|
+
persistReport,
|
|
525
|
+
getMcpPoolStats,
|
|
526
|
+
resetMcpPool,
|
|
527
|
+
}
|