WardrikResearch

Copy Markdown

Deep research for agents. It splits a topic into angles, researches each one in its own subagent at the same time, and combines the findings into one report.

def deps do
  [
    {:wardrik_research, "~> 0.1.0-rc.1"}
  ]
end

Usage

Give an agent WardrikResearch next to a search tool. The agent calls it as deep_research:

WardrikCore.start_agent(
  agent_id: "acme/analyst",
  model: "anthropic:claude-haiku-4-5",
  capabilities: [{WardrikBrave, brave: MyApp.Brave}, WardrikResearch]
)

In Wardrik, offer it by name. A definition then lists that name in its tools:

config :my_app, MyApp.AgentRuntime,
  capabilities: [web_search: {WardrikBrave, brave: MyApp.Brave}, deep_research: WardrikResearch]

The daemon offers it as deep_research.

Options

{WardrikResearch,
 angles: [
   %{angle: "pricing and packaging", prompt: "Think like a pricing analyst."},
   %{angle: "recent developments"}
 ],
 max_concurrency: 3}
  • :angles - the angles a topic is split into, each %{angle: name} with an optional :prompt added to that researcher's instructions. Five general angles unless set.
  • :max_concurrency - how many researchers run at once. 5 unless set.
  • :timeout - how long one researcher may take, in milliseconds. 8 minutes unless set.
  • :max_rounds - how many model calls one researcher may make. 12 unless set.

The agent may also pass its own angles for a single call.

How it runs

Each researcher is a subagent of the calling agent, made with WardrikCore.subagent/3:

  • It runs on the agent's model, middleware and tools, except deep_research. A researcher can't start research of its own.
  • Without a search tool, it only knows what the model knows.
  • What it spends counts toward the agent's budgets.
  • What it reads labels the answer, as if the agent had read it.
  • A call that would wait for a person ends that researcher's angle.

Result

The tool returns a map:

%{
  "topic" => "AI code review tools",
  "report" => "...",
  "gaps" => [%{"angle" => "where this appears to be heading", "reason" => "it ran out of time"}]
}

A failed or timed-out angle is listed in "gaps", and the rest are still combined. The call is an error only when every angle fails.

Each researcher shows up in the agent's events as wardrik.subagent.started, then wardrik.subagent.completed or wardrik.subagent.failed.