Class: Flunky::Tools

Inherits:
Object
  • Object
show all
Defined in:
lib/flunky/tools.rb

Overview

Turns a session into the two things a model client needs: a list of tool schemas to advertise, and a dispatcher that runs a named tool call.

The schema shape (name/description/input_schema) is what Anthropic expects directly; the example adapter shows the one-line wrap for OpenAI.

Instance Method Summary collapse

Constructor Details

#initialize(session) ⇒ Tools

Returns a new instance of Tools.



10
11
12
# File 'lib/flunky/tools.rb', line 10

def initialize(session)
  @session = session
end

Instance Method Details

#definitionsObject



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/flunky/tools.rb', line 14

def definitions
  [
    tool("navigate", "Load a URL in the browser.",
         url: { type: "string", description: "Absolute URL to open" }),
    tool("click", "Click the element with the given ref.",
         ref: { type: "integer", description: "Element ref from the page snapshot" }),
    tool("type", "Type text into the element with the given ref (clears it first).",
         ref: { type: "integer" }, text: { type: "string" }),
    tool("fill_in", "Fill a field found by its label or placeholder text.",
         label: { type: "string" }, text: { type: "string" }),
    tool("select", "Select an option in a dropdown element.",
         ref: { type: "integer" }, value: { type: "string" }),
    tool("press", "Press a key, for example Enter or Tab.",
         key: { type: "string" }),
    tool("scroll", "Scroll the page in a direction.",
         direction: { type: "string", enum: %w[up down left right] }),
    tool("read_page", "Re-read the page and return a fresh snapshot.")
  ]
end

#dispatch(name, args = {}) ⇒ Object

Run a tool by name, normalize the result, and fold a fresh page view in so the model always sees the outcome of what it just did.



36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/flunky/tools.rb', line 36

def dispatch(name, args = {})
  args = symbolize(args)
  result =
    case name.to_s
    when "navigate" then @session.actions.navigate(args[:url])
    when "click" then @session.actions.click(args[:ref])
    when "type" then @session.actions.type(args[:ref], args[:text])
    when "fill_in" then @session.actions.fill_in(args[:label], with: args[:text])
    when "select" then @session.actions.select(args[:value], ref: args[:ref])
    when "press" then @session.actions.press(args[:key])
    when "scroll" then @session.actions.scroll(args[:direction])
    when "read_page" then { ok: true, message: "read page" }
    else raise UnknownTool, "unknown tool #{name.inspect}"
    end

  result.merge(page: @session.observe.to_prompt)
rescue Flunky::Error => e
  raise if e.is_a?(UnknownTool)

  { ok: false, error: e.message }
end