接入位表六家扩到八家,端点形状与错误码一字未改(契约 v0.87,仅两处名单)。
- tencent_wsa:POST {base}/SearchPro + Authorization Bearer,零签名。
两条官方口径决定实现:HTTP 状态码恒 200(判失败只能读 Response.Error.Code);
Pages 是「JSON 字符串数组」需二次解析。错误码按官方表分类
(UnauthorizedOperation/AuthFailure.* = 凭据、ResourceUnavailable = 欠费、
RequestLimitExceeded* = 限流),文案只带 code 不带上游 Message。
- metaso:POST {base}/api/v1/search,响应 schema 仅第三方来源且互相打架,
实现走宽松解析(数组候选与字段名回退),逐处标「未实测」。
- 零新 env 键:两家只走 $DATA_DIR/config/plugins/web-search.json,
.env / .env.example 未动;组合根 websearch_providers.go 零功能改动。
- 契约 v0.87:values.provider 合法闭集与 plugin.providers 候选各加两条,
计数不变(14 + 25 + 40 = 79)。
59 lines
3.9 KiB
Go
59 lines
3.9 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 / tencent_wsa / metaso; 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. 取正文走
|
||
// **降级链**(design/28 §1 M5 / §8 B5):直连 fetch →(失败 / 判定为动态页)
|
||
// ⇒ 浏览器渲染取正文,返回体用 `fetchedBy`(direct / browser)**如实标注实际
|
||
// 走了哪条**,两条档的失败原文分别留在 directError / browserError 里 —— 绝不静默
|
||
// 替换、绝不把失败说成成功。这一档**默认关**(WithBrowserFallback);被 SSRF
|
||
// 判定拒绝的目标**不换路**(换条路访问同一目标是绕过判定,不是降级)。
|
||
// - 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
|