Files
Cyrene_v2/plugins/tools/io/doc.go
T
AskaEth c2e413ec38
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
feat(io): web-fetch 直连→浏览器渲染降级档 + fetchedBy 如实标注(Z5 机制)
- 降级链:直连失败 / 判定为动态页 ⇒ 浏览器渲染取正文;返回体带 fetchedBy=direct|browser,
  两条档的失败各自留痕(directError/browserError/browserSource/dynamicSuspect),**绝不静默替换**
- 被 SSRF 拒绝的目标**不换路**(红线);渲染器缺位时如实报双失败
- 3 个变异自检(去掉动态页判据 / 去掉 SSRF 短路 / 掩盖双失败)
⚠️ **生产接不通**:internal/capability/browser 没有「取正文」入口(不在本片文件面)⇒
   开关默认关、不假装可用;解封形状已在报告里给出(加 RenderText ≈40 行)
2026-10-07 09:34:47 +08:00

58 lines
3.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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. 取正文走
// **降级链**(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