Skip to main content

examples/branching/actions/analysis_answer.ex

defmodule Jido.Runic.Examples.Branching.Actions.AnalysisAnswer do
  @moduledoc """
  Produce a deeper synthesized answer from an analysis plan.
  """

  @output_schema [
    branch: [type: :atom, required: true],
    branch_result: [type: :string, required: true],
    explanation: [type: :string, required: true],
    route_confidence: [type: :float, required: true],
    analysis_plan: [type: :any, required: true],
    key_risks: [type: :any, required: true]
  ]

  use Jido.Action,
    name: "branching_analysis_answer",
    description: "Synthesizes a deep answer from planned analysis",
    schema: [
      question: [type: :string, required: true],
      route: [type: :atom, required: true],
      detail_level: [type: :atom, required: true],
      confidence: [type: :float, required: true],
      reasoning: [type: :string, required: true],
      analysis_plan: [type: :any, required: true],
      key_risks: [type: :any, required: true]
    ],
    output_schema: @output_schema

  alias Jido.Runic.Examples.Studio.Actions.Helpers

  @impl true
  def run(
        %{
          question: question,
          route: :analysis,
          detail_level: detail_level,
          confidence: confidence,
          reasoning: reasoning,
          analysis_plan: analysis_plan,
          key_risks: key_risks
        },
        _context
      ) do
    plan_text = bullets(analysis_plan)
    risks_text = bullets(key_risks)

    prompt = """
    You are a senior architect.
    Use the analysis plan and risks to answer this question:

    Question: "#{question}"

    Analysis plan:
    #{plan_text}

    Risks/constraints:
    #{risks_text}

    Write a #{answer_style(detail_level)} answer in markdown with:
    - Recommended approach
    - Tradeoffs
    - 2-4 concrete next steps
    """

    case Helpers.llm_call(prompt, model: :capable, temperature: 0.5, max_tokens: 900) do
      {:ok, text} ->
        {:ok,
         %{
           branch: :analysis,
           branch_result: text,
           explanation: reasoning,
           route_confidence: confidence,
           analysis_plan: List.wrap(analysis_plan),
           key_risks: List.wrap(key_risks)
         }}

      {:error, reason} ->
        {:error, reason}
    end
  end

  def run(%{route: route}, _context) do
    {:error, {:invalid_branch_input, {:expected_analysis_route, route}}}
  end

  defp answer_style(:detailed), do: "detailed"
  defp answer_style(_), do: "compact but concrete"

  defp bullets(values) do
    values
    |> List.wrap()
    |> Enum.map_join("\n", fn value -> "- #{value}" end)
  end
end