主人报的故障:她调 web-search 必失败(no search endpoint configured)。根因两条:组合根从未注入 WithSearchEndpoint + 配置层根本没有搜索配置项。 - internal/config/websearch.go:WEB_SEARCH_ENDPOINT(默认本机兜底 http://127.0.0.1:38471)+ WEB_SEARCH_TIMEOUT;ResolveEndpoint() 三态裁决(可用/显式关闭/非法),非法值启动即报错 - cmd/cyrene/wire_io_tools.go:组合根唯一的 io 选项装配点;端点不可用 ⇒ WithoutSearch() + 带 source 的 WARN(只记键名与原因,不打印 URL 值) - plugins/tools/io:新增 WithoutSearch()(**根本不进注册面** ⇒ 模型看不见)+ WithSearchTimeout();协议解析逻辑一字未动 - 隐蔽坑(额外查出并修):SearXNG 对 /?q= 回 308 → /search,重定向那一跳走**共享 SSRF 白名单** ⇒ 只注入端点照样被拦。改为**只给 web-search 一件**加宽自己的客户端与白名单,共享白名单与 http/web-fetch 客户端一字未动(有测试钉住它仍拒绝本机网关地址) - .env.example 新增 2 键 + 注释说明「空串/off/none = 不注册」 - 真机 e2e 两次绿(SearXNG 返回 9 条);变异:不注入端点 / 关闭态仍注册 / 默认值改错 / 不并入端点主机 / 重定向用共享白名单 ⇒ 5 条全红
47 lines
2.7 KiB
Go
47 lines
2.7 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 SearXNG-compatible endpoint. When no
|
|
// usable endpoint 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. The endpoint itself is operator configuration (the model only
|
|
// supplies the query), hence its host is trusted by this tool alone: a
|
|
// loopback fallback endpoint stays reachable without widening the shared
|
|
// http/web-fetch allowlist.
|
|
// - 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
|