Class: WebGetToolDecorator

Inherits:
ToolDecorator show all
Defined in:
app/decorators/web_get_tool_decorator.rb

Overview

Transforms Tools::WebGet responses for LLM consumption by detecting the Content-Type header and applying format-specific conversion.

Content-Type maps to a method name via simple string normalization:

"application/json" → {#application_json}
"text/html"        → {#text_html}
"text/plain"       → method_missing → passthrough

Adding a new format = adding one method. Unknown types fall through #method_missing and pass through unchanged.

Examples:

decorator = WebGetToolDecorator.new
decorator.call(body: "<h1>Hi</h1>", content_type: "text/html")
#=> "[Converted: HTML → Markdown]\n\n# Hi"

Constant Summary collapse

NOISE_TAGS =

HTML elements that carry no useful content for an LLM.

%w[script style nav footer aside form noscript iframe
svg header menu menuitem].freeze

Constants inherited from ToolDecorator

ToolDecorator::DECORATOR_MAP

Instance Method Summary collapse

Methods inherited from ToolDecorator

call

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(_method_name, body) ⇒ Hash

Passthrough for unregistered content types.

Returns:

  • (Hash)

    ‘String, meta: nil`



73
74
75
# File 'app/decorators/web_get_tool_decorator.rb', line 73

def method_missing(_method_name, body, *)
  {text: body, meta: nil}
end

Instance Method Details

#application_json(body) ⇒ Hash

Compresses JSON using TOON (Token-Optimized Object Notation) for ~40% token savings on typical JSON arrays.

Parameters:

  • body (String)

    JSON response body

Returns:

  • (Hash)

    ‘String, meta: String`



53
54
55
56
57
58
# File 'app/decorators/web_get_tool_decorator.rb', line 53

def application_json(body)
  parsed = JSON.parse(body)
  {text: Toon.encode(parsed), meta: "[Converted: JSON → TOON]"}
rescue JSON::ParserError
  {text: body, meta: nil}
end

#call(result) ⇒ String

Returns LLM-optimized content with conversion metadata tag.

Parameters:

  • result (Hash)

    ‘String, content_type: String`

Returns:

  • (String)

    LLM-optimized content with conversion metadata tag



28
29
30
31
32
33
34
35
36
# File 'app/decorators/web_get_tool_decorator.rb', line 28

def call(result)
  return result.to_s unless result.is_a?(Hash) && result.key?(:body)

  body = result[:body].to_s
  content_type = result[:content_type] || "text/plain"
  decorated = decorate(body, content_type: content_type)

  assemble(**decorated)
end

#decorate(body, content_type:) ⇒ Hash

Dispatches to the format-specific method derived from Content-Type.

Parameters:

  • body (String)

    raw response body

  • content_type (String)

    HTTP Content-Type header value

Returns:

  • (Hash)

    ‘String, meta: String|nil`



43
44
45
46
# File 'app/decorators/web_get_tool_decorator.rb', line 43

def decorate(body, content_type:)
  method_name = content_type.split(";").first.strip.tr("/", "_").tr("-", "_")
  public_send(method_name, body)
end

#respond_to_missing?Boolean

Returns:

  • (Boolean)


77
78
79
# File 'app/decorators/web_get_tool_decorator.rb', line 77

def respond_to_missing?(*, **)
  true
end

#text_html(body) ⇒ Hash

Strips noise elements (scripts, styles, nav, ads) and converts semantic HTML to Markdown for clean LLM consumption.

Parameters:

  • body (String)

    HTML response body

Returns:

  • (Hash)

    ‘String, meta: String`



65
66
67
68
# File 'app/decorators/web_get_tool_decorator.rb', line 65

def text_html(body)
  markdown = html_to_markdown(body)
  {text: markdown, meta: "[Converted: HTML → Markdown]"}
end