Class: Kodo::Tools::FetchUrl
- Inherits:
-
RubyLLM::Tool
- Object
- RubyLLM::Tool
- Kodo::Tools::FetchUrl
- Extended by:
- PromptContributor
- Defined in:
- lib/kodo/tools/fetch_url.rb
Constant Summary collapse
- MAX_PER_TURN =
3- MAX_CONTENT_LENGTH =
50_000- MAX_REDIRECTS =
5- READ_TIMEOUT =
15- OPEN_TIMEOUT =
10- USER_AGENT =
"Kodo/#{VERSION} (bot; +https://kodo.bot)".freeze
- BLOCKED_RANGES =
RFC 1918, loopback, link-local
[ IPAddr.new('10.0.0.0/8'), IPAddr.new('172.16.0.0/12'), IPAddr.new('192.168.0.0/16'), IPAddr.new('127.0.0.0/8'), IPAddr.new('169.254.0.0/16'), IPAddr.new('0.0.0.0/8'), IPAddr.new('::1/128'), IPAddr.new('fc00::/7'), IPAddr.new('fe80::/10') ].freeze
Instance Attribute Summary collapse
-
#turn_context ⇒ Object
writeonly
Sets the attribute turn_context.
Instance Method Summary collapse
- #execute(url:) ⇒ Object
-
#initialize(audit:) ⇒ FetchUrl
constructor
A new instance of FetchUrl.
- #name ⇒ Object
- #reset_turn_count! ⇒ Object
Methods included from PromptContributor
capability_name, capability_primary, disabled_guidance, enabled_guidance
Constructor Details
#initialize(audit:) ⇒ FetchUrl
Returns a new instance of FetchUrl.
46 47 48 49 50 51 |
# File 'lib/kodo/tools/fetch_url.rb', line 46 def initialize(audit:) super() @audit = audit @turn_count = 0 @turn_context = nil end |
Instance Attribute Details
#turn_context=(value) ⇒ Object (writeonly)
Sets the attribute turn_context
44 45 46 |
# File 'lib/kodo/tools/fetch_url.rb', line 44 def turn_context=(value) @turn_context = value end |
Instance Method Details
#execute(url:) ⇒ Object
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/kodo/tools/fetch_url.rb', line 57 def execute(url:) @turn_count += 1 if @turn_count > MAX_PER_TURN return "Rate limit reached (max #{MAX_PER_TURN} fetches per message). Try again next message." end uri = validate_url(url) return uri if uri.is_a?(String) # error message content = fetch_with_redirects(uri) return content if content.is_a?(String) && content.start_with?('Error:') text = extract_text(content) text = text[0...MAX_CONTENT_LENGTH] if text.length > MAX_CONTENT_LENGTH # Audit-log injection signals (detection only — not a security boundary) if Kodo.config.web_injection_scan? scan = Web::InjectionScanner.scan(text) if scan.suspicious? @audit.log( event: 'injection_suspected', detail: "url:#{Kodo.config.web_audit_urls? ? url : '[redacted]'} signals:#{scan.signal_count}" ) end end audit_url = Kodo.config.web_audit_urls? ? url : '[redacted]' @audit.log( event: 'url_fetched', detail: "url:#{audit_url} len:#{text.length}" ) # Mark that web content was fetched this turn (used by RememberFact gate) @turn_context&.web_fetched! result = text.empty? ? "No readable content found at #{url}" : text wrap_as_untrusted(url, result) rescue Kodo::Error => e e. end |
#name ⇒ Object
98 99 100 |
# File 'lib/kodo/tools/fetch_url.rb', line 98 def name 'fetch_url' end |
#reset_turn_count! ⇒ Object
53 54 55 |
# File 'lib/kodo/tools/fetch_url.rb', line 53 def reset_turn_count! @turn_count = 0 end |