主人定调「先把原生的做进插件,MCP 路线等后端 MCP 完善后再接」。 - 新包 plugins/tools/io/search/:一 provider 一文件 + 共享 http/提取器 + 归一化 Result;域名过滤/去重/排序**归一化后统一做一次** - 配置 15 键:WEB_SEARCH_PROVIDER(默认 searxng)/_FALLBACK/_MAX_RESULTS + 五家 ×(API_KEY/BASE_URL);WEB_SEARCH_TIMEOUT 语义改为「**每次上游尝试**」(降级链才有意义) - 硬语义:未注册/未配置的主 provider ⇒ **启动期报错**(不许静默回落);off ⇒ 不注册工具;缺 key 的家不进可用清单;降级链**如实标实际应答的 provider**(变异:拿主力冒充 ⇒ 测试红「provider = zhipu, want bocha」) - 密钥绝不进日志/响应(有断言);错误分类(鉴权/限流/额度/网络)+ **空结果 ≠ 成功**(变异暴露过一个死分支⇒下移到 searchWith 修掉) - searxng 真机 e2e 通过(provider=searxng 5 条);**其余五家无 key ⇒ 如实标未实测**;契约无改动(无新端点、工具 schema 不变) - 注册表留好 B 档接入位(tavily/exa/firecrawl/serper/serpapi),并有「未登记⇒启动报错」的防回归断言
53 lines
3.3 KiB
Go
53 lines
3.3 KiB
Go
// Package io implements the built-in I/O and network tools for Cyrene v2
|
|
// (DevDocs/design/09-插件生态.md). It exposes file, image-crop, document-read, http,
|
|
// web-search, web-fetch and knowledge as pkg/plugins/sdk.Tool values, wired to the
|
|
// process-internal config, logger and runtime/memory retriever.
|
|
//
|
|
// Build the full configured tool set with New(cfg, opts...). Tools() and
|
|
// Register(reg) are convenience wrappers that use platform defaults; production
|
|
// wiring should call New(cfg, opts...) so the tools honor the real DataDir,
|
|
// search endpoint and knowledge retriever.
|
|
//
|
|
// Security constraints
|
|
//
|
|
// - file: every path is cleaned and validated to stay inside the configured
|
|
// data directory or an explicit whitelist; ".." traversal and symlink escape
|
|
// are rejected; reads and writes are size-capped.
|
|
// - image-crop: crops a region out of a large image so the agent can read it in
|
|
// parts (an image service downsamples big images); path sources go through the
|
|
// file sandbox, URL sources through the SSRF guard, and the returned data URI
|
|
// is size-capped.
|
|
// - http: GET/POST only, timeouts, response truncation and SSRF protection
|
|
// (loopback/private/link-local addresses and localhost are refused unless
|
|
// the host is on an explicit allowlist).
|
|
// - web-search: queries the configured search **provider** through the registry in
|
|
// plugins/tools/io/search (searxng / zhipu / aliyun_iqs / bocha / volcengine /
|
|
// baidu_qianfan; one provider per file, design/27 §4). The model sees exactly one
|
|
// tool whose schema never changes with the backend. A configured fallback chain is
|
|
// tried in order, and only an *unavailable* provider (missing key, auth / rate
|
|
// limit / quota / network failure) advances the chain — an empty result set does
|
|
// not, and it is reported as "no results" rather than as success. The result names
|
|
// the provider that actually answered. When no usable backend is configured the
|
|
// composition root passes WithoutSearch, so the tool is not registered at all — the
|
|
// model never sees a tool that could only error. Provider endpoints are operator
|
|
// configuration (the model only supplies the query), hence their hosts are trusted
|
|
// by this tool alone: a loopback fallback endpoint stays reachable without widening
|
|
// the shared http/web-fetch allowlist. API keys never reach logs, results or prompts.
|
|
// - web-fetch: size- and content-type-limited readable text extraction.
|
|
// - knowledge: RAG lookup over the runtime memory retriever; a clear message
|
|
// when no knowledge base is configured.
|
|
//
|
|
// # File-level mutual exclusion
|
|
//
|
|
// The two tools that touch files declare the file each call will touch
|
|
// (tool.FileTargeter, implemented in file_targets.go): file declares read for
|
|
// read/list/search and write for write; image-crop declares a read when its image
|
|
// is a local path. When another in-flight parallel leg is already operating on that
|
|
// same file, the call returns tool.ErrFileBusy with the file's state instead of
|
|
// running or queueing; two reads of one file still run in parallel, and calls that
|
|
// cannot touch a file (a sandbox-rejected path, an HTTP or data: URI source) declare
|
|
// nothing and keep their previous behavior.
|
|
//
|
|
// All tools are safe for concurrent use, as required by sdk.Tool.
|
|
package io
|