Powered by AppSignal & Oban Pro

Jidoka: Web Tools

livebook/12_web_tools.livemd

Jidoka: Web Tools

Run in Livebook

Web access is a constrained capability. Jidoka exposes search and read-only page tools without exposing arbitrary browser control to the model.

Setup

Mix.install(
  [
    {:jidoka, git: "https://github.com/mikehostetler/jidoka.git", ref: "924a486f3c1b7e7a943cb3d5ceee0de65f158467"},
    {:kino, "~> 0.19.0"}
  ],
  config: [
    jidoka: [
      model_aliases: %{fast: "anthropic:claude-haiku-4-5"}
    ]
  ]
)
Jidoka.Kino.setup()

Define Web Agents

defmodule LivebookDemo.Web.SearchAgent do
  use Jidoka.Agent

  agent do
    id :livebook_web_search_agent
  end

  defaults do
    model :fast
    instructions "You can search the public web."
  end

  capabilities do
    web :search
  end
end

defmodule LivebookDemo.Web.ReadOnlyAgent do
  use Jidoka.Agent

  agent do
    id :livebook_web_read_only_agent
  end

  defaults do
    model :fast
    instructions "You can search and read public web pages."
  end

  capabilities do
    web :read_only
  end
end

Compare the exposed tools.

[
  %{
    agent: "search",
    web_tool_names: LivebookDemo.Web.SearchAgent.web_tool_names(),
    tool_names: LivebookDemo.Web.SearchAgent.tool_names()
  },
  %{
    agent: "read_only",
    web_tool_names: LivebookDemo.Web.ReadOnlyAgent.web_tool_names(),
    tool_names: LivebookDemo.Web.ReadOnlyAgent.tool_names()
  }
]

Safety Boundary

Read-only page tools reject localhost, loopback, and private network URLs before browser work starts.

{:error, read_error} = Jidoka.Web.Tools.ReadPage.run(%{url: "http://localhost:4000"}, %{})
{:error, snapshot_error} = Jidoka.Web.Tools.SnapshotUrl.run(%{url: "http://192.168.1.10"}, %{})

Jidoka.Kino.table("Web safety checks", [
  %{tool: "read_page", message: Jidoka.format_error(read_error)},
  %{tool: "snapshot_url", message: Jidoka.format_error(snapshot_error)}
])

Inspect the read-only agent like any other tool-bearing agent.

{:ok, definition} = Jidoka.inspect_agent(LivebookDemo.Web.ReadOnlyAgent)
Map.take(definition, [:id, :tool_names, :web])

Optional Provider Turn

{:ok, pid} =
  Jidoka.Kino.start_or_reuse("livebook-web-read-only-agent", fn ->
    LivebookDemo.Web.ReadOnlyAgent.start_link(id: "livebook-web-read-only-agent")
  end)

Jidoka.Kino.chat("Web-capable chat", fn ->
  LivebookDemo.Web.ReadOnlyAgent.chat(pid, "What web tools are available to you?")
end)