Skip to main content

examples/deepagents/support/support.exs

Code.require_file("../../support.exs", __DIR__)

defmodule BeamWeaver.Examples.DeepAgents.Support do
  @moduledoc false

  alias BeamWeaver.Agent
  alias BeamWeaver.Agent.Middleware.ToolSelection
  alias BeamWeaver.ExecutionPolicy
  alias BeamWeaver.Examples.Support

  @node_timeout 60_000

  @concise_suffix """
  Complete the user's request with one concise sentence. Do not call tools unless
  absolutely necessary.
  """

  def create(opts) do
    opts =
      opts
      |> add_concise_prompt()
      |> maybe_disable_visible_tools()
      |> Keyword.put_new(:model_opts, default_model_opts())

    case Agent.build(opts) do
      {:ok, agent} -> {:ok, extend_timeout(agent)}
      other -> other
    end
  end

  def model, do: Support.model()

  defp default_model_opts do
    base = [max_tokens: 256, max_output_tokens: 256, timeout: @node_timeout]

    if String.starts_with?(Support.model_id(), "zai:") do
      base
    else
      Keyword.put(base, :tool_choice, "none")
    end
  end

  defp add_concise_prompt(opts) do
    Keyword.update(opts, :system_prompt, @concise_suffix, fn
      nil -> @concise_suffix
      prompt -> to_string(prompt) <> "\n\n" <> @concise_suffix
    end)
  end

  defp maybe_disable_visible_tools(opts) do
    if String.starts_with?(Support.model_id(), "zai:") do
      Keyword.update(opts, :middleware, [ToolSelection.new(allow: [])], fn middleware ->
        List.wrap(middleware) ++ [ToolSelection.new(allow: [])]
      end)
    else
      opts
    end
  end

  defp extend_timeout(agent), do: update_in(agent.compiled, &extend_compiled_timeout/1)

  defp extend_compiled_timeout(compiled) do
    graph = extend_graph_timeout(compiled.graph)
    %{compiled | graph: graph, plan: %{compiled.plan | graph: graph}}
  end

  defp extend_graph_timeout(graph) do
    nodes =
      Map.new(graph.nodes, fn {name, spec} ->
        {name, %{spec | timeout: @node_timeout, execution_policy: ExecutionPolicy.new!(timeout: @node_timeout)}}
      end)

    %{graph | nodes: nodes}
  end
end