Module: Pikuri::Tool::Fetch
- Defined in:
- lib/pikuri/tool/fetch.rb
Overview
Truncation policy and Tool spec for the fetch tool. HTTP work lives in
Scraper.fetch; this wrapper accepts only textual content-types,
applies a character cap, and exposes the result in OpenAI tool-call shape.
Sister of WebScrape but with no extraction pass — bodies are
returned verbatim, for raw textual data (JSON APIs, CSV, robots.txt,
sitemaps, source files) where a rendering pass would corrupt the payload.
Constant Summary collapse
- DEFAULT_MAX_CHARS =
Returns default character cap on the body from fetch. Smaller than WebScrape::DEFAULT_MAX_CHARS because fetch's content is bimodal — most JSON/XML/CSV is tiny, and large dumps are better re-requested deliberately than padded into every default.
5_000- MAX_MAX_CHARS =
Returns hard ceiling on fetch's
max_chars; matches WebScrape::MAX_MAX_CHARS. 100_000- TEXTUAL_APPLICATION_TYPES =
Application content-types that are textual in practice, so safe to return verbatim despite failing the
text/*check. Anything outsidetext/*and this list is refused. %w[ application/json application/xml application/javascript application/xhtml+xml application/rss+xml application/atom+xml ].freeze
- CACHE =
On-disk cache for fetch, in its own subdir so a
fetchand aweb_scrapeon the same URL don't collide (raw body vs extracted Markdown). A method so specs can swap UrlCache::NULL. UrlCache.new(ttl: UrlCache::DEFAULT_TTL, dir: "#{UrlCache::ROOT_DIR}/fetch")
Class Method Summary collapse
-
.cache ⇒ UrlCache, #fetch
Accessor for CACHE; specs swap in UrlCache::NULL or an isolated cache.
-
.download(url) ⇒ String
GET
urland verify the content-type is textual. -
.fetch(url, max_chars: DEFAULT_MAX_CHARS) ⇒ String
Download
urlvia Scraper.fetch and return the body verbatim, if the content-type is textual (anytext/*plus TEXTUAL_APPLICATION_TYPES); anything else (PDF, image, binary) yields an"Error: ..."string. -
.textual?(content_type) ⇒ Boolean
True when
text/*or in TEXTUAL_APPLICATION_TYPES. -
.truncate(body, max_chars) ⇒ String
Cut
bodyto at mostmax_chars, appending a marker with the original length when truncation happens.
Class Method Details
.cache ⇒ UrlCache, #fetch
Accessor for CACHE; specs swap in UrlCache::NULL or an isolated cache.
44 45 46 |
# File 'lib/pikuri/tool/fetch.rb', line 44 def self.cache CACHE end |
.download(url) ⇒ String
GET url and verify the content-type is textual. Always hits the
network (caller caches/truncates).
77 78 79 80 81 82 83 84 |
# File 'lib/pikuri/tool/fetch.rb', line 77 def self.download(url) fetched = Scraper.fetch(url) return fetched.body if textual?(fetched.content_type) raise Scraper::FetchError, "refused to fetch #{url}: content-type #{fetched.content_type.inspect} " \ 'is not textual (use web_scrape for rendered pages)' end |
.fetch(url, max_chars: DEFAULT_MAX_CHARS) ⇒ String
Download url via Scraper.fetch and return the body verbatim,
if the content-type is textual (any text/* plus
TEXTUAL_APPLICATION_TYPES); anything else (PDF, image, binary) yields
an "Error: ..." string. Cached on disk keyed by URL; max_chars is
not in the key (values share one entry, truncation runs after the
lookup). Cached only on success — Scraper::FetchError is caught
outside cache.fetch, so failures are never persisted; other
exceptions bubble up.
62 63 64 65 66 67 68 |
# File 'lib/pikuri/tool/fetch.rb', line 62 def self.fetch(url, max_chars: DEFAULT_MAX_CHARS) max_chars = max_chars.clamp(1, MAX_MAX_CHARS) body = cache.fetch(url) { download(url) } truncate(body, max_chars) rescue Scraper::FetchError => e "Error: #{e.}" end |
.textual?(content_type) ⇒ Boolean
Returns true when text/* or in TEXTUAL_APPLICATION_TYPES.
88 89 90 91 |
# File 'lib/pikuri/tool/fetch.rb', line 88 def self.textual?(content_type) content_type.start_with?('text/') || TEXTUAL_APPLICATION_TYPES.include?(content_type) end |
.truncate(body, max_chars) ⇒ String
Cut body to at most max_chars, appending a marker with the original
length when truncation happens. Same shape as WebScrape.truncate.
99 100 101 102 103 104 105 |
# File 'lib/pikuri/tool/fetch.rb', line 99 def self.truncate(body, max_chars) return body if body.length <= max_chars "#{body[0, max_chars]}\n\n" \ "... [truncated at #{max_chars} of #{body.length} chars; " \ 'call again with a larger `max_chars` to see more]' end |