/* global React */

function Chapter06() {
  return (
    <section className="chapter" id="ch-06" data-screen-label="06 Agent types">
      <div className="chapter-header">
        <div className="eyebrow">Chapter 06 · Agent types</div>
        <h1 className="chapter-title">ReAct, OpenAI tools, structured chat — what they really are.</h1>
        <p className="chapter-lede">
          "Agent type" sounds intimidating; it's just a different way the LLM signals "call a tool." Three flavors: text
          parsing (ReAct), native tool calling (OpenAI tools), and JSON-only (structured chat).
        </p>
      </div>

      <SectionTitle num="6.1">ReAct — Reason + Act in plain text</SectionTitle>
      <p>
        ReAct is the OG pattern (Yao et al., 2022). It predates native tool calling. The trick: ask the model to write a
        rigid text format and parse its output yourself.
      </p>
      <CodeBlock file="react_prompt.txt" lang="text">{`Answer the following question using available tools.

You have access to:
  get_weather(city: str) - returns current weather
  search_web(query: str) - searches the web

Use this exact format:
  Thought: <your reasoning>
  Action: <tool_name>
  Action Input: <JSON args>
  Observation: <tool result will be inserted here>
  ... (repeat as needed)
  Thought: I now know the final answer.
  Final Answer: <answer>

Question: {input}
{agent_scratchpad}`}</CodeBlock>

      <p>
        The runtime parses each <code>Thought / Action / Action Input</code> block, runs the tool, injects the
        <code>Observation:</code> back into the prompt, and the model continues. Watch one play out:
      </p>

      <ReactTrace />

      <Callout kind="gotcha" title="ReAct is fragile">
        If the model emits malformed text (extra newline, wrong key) the parser breaks. Modern code uses native tool
        calling whenever the model supports it. Keep ReAct in your back pocket for local models without function
        calling.
      </Callout>

      <SectionTitle num="6.2">OpenAI tools agent — native tool calling</SectionTitle>
      <p>
        When the model API supports tool calling natively (GPT-4, Claude 3+, Gemini 1.5+), you don't need text parsing.
        The model returns a structured <code>tool_calls</code> field. LangChain's <code>create_tool_calling_agent</code>
        is the modern default:
      </p>
      <CodeBlock file="tool_calling_agent.py">{`from langchain.agents import AgentExecutor, create_tool_calling_agent
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder

prompt = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    MessagesPlaceholder("chat_history", optional=True),
    ("human", "{input}"),
    MessagesPlaceholder("agent_scratchpad"),
])

agent = create_tool_calling_agent(model, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

executor.invoke({"input": "What's the weather in Tokyo?"})`}</CodeBlock>

      <p>This is what 90% of new code uses. It's the same idea as ReAct, but the loop is driven by structured fields instead of regex.</p>

      <SectionTitle num="6.3">Structured chat — JSON-everything</SectionTitle>
      <p>
        For models that <em>don't</em> have native tool calling but <em>do</em> reliably emit JSON (smaller open-source
        models, often), the structured chat agent forces JSON output:
      </p>
      <CodeBlock file="structured_chat.py">{`from langchain.agents import create_structured_chat_agent

# Same idea, but the model must respond with:
# {"action": "tool_name", "action_input": {...}}
# or
# {"action": "Final Answer", "action_input": "the answer"}

agent = create_structured_chat_agent(model, tools, prompt)`}</CodeBlock>

      <SectionTitle num="6.4">The 3-way comparison — exactly what differs</SectionTitle>
      <p>
        Same loop, three different ways to extract "what does the model want to do next?" from its output. Here's a
        scannable side-by-side:
      </p>

      <div className="comparison-table">
        <table>
          <thead>
            <tr>
              <th></th>
              <th>ReAct</th>
              <th>Structured Chat</th>
              <th>Tool Calling</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td>Who defines the format?</td>
              <td>LangChain prompt</td>
              <td>LangChain prompt</td>
              <td>Model provider (OpenAI/Anthropic)</td>
            </tr>
            <tr>
              <td>How is output parsed?</td>
              <td>Regex / string split</td>
              <td><code>json.loads()</code></td>
              <td>SDK deserializes API field</td>
            </tr>
            <tr>
              <td>Model requirement</td>
              <td>Can follow instructions</td>
              <td>Can output valid JSON</td>
              <td>Fine-tuned for tool use</td>
            </tr>
            <tr>
              <td>Failure mode</td>
              <td><span className="bad">Silent — wrong parse</span></td>
              <td><span className="warn">Loud — JSON error thrown</span></td>
              <td><span className="good">Rare — schema enforced</span></td>
            </tr>
            <tr>
              <td>Prompt-injection risk?</td>
              <td>Yes</td>
              <td>Yes</td>
              <td>No — goes in API <code>tools=</code> field</td>
            </tr>
            <tr>
              <td>AgentExecutor needed?</td>
              <td>✅ Yes</td>
              <td>✅ Yes</td>
              <td>✅ Yes</td>
            </tr>
          </tbody>
        </table>
      </div>

      <p>
        Notice the bottom row — the executor is identical across all three. The only thing that changes is the parser
        wrapped around the LLM call. That's why the framework can offer them as drop-in alternatives.
      </p>

      <SectionTitle num="6.5">Choosing one (decision tree)</SectionTitle>

      <h4 className="mini-title">Timeline of need</h4>
      <CodeBlock file="timeline.txt" lang="text">{`2022 ──► ReAct            (any model, just follow text format)
2023 ──► Structured Chat  (models that reliably emit JSON)
2023 ──► Tool Calling     (GPT-4, Claude 3 — API-level support)
2024 ──► LangGraph        (replaces AgentExecutor entirely)`}</CodeBlock>

      <p>
        Each row was a response to a real ceiling in the row above. ReAct works on anything but parses brittlely.
        Structured chat hardens the parser but still embeds the contract in the prompt. Tool calling pushes the contract
        into the API itself. LangGraph then says "the loop deserves to be a graph" and rewrites the runtime around state
        and persistence. Knowing the order makes the design choices feel obvious instead of arbitrary.
      </p>

      <CodeBlock file="decision_tree.txt" lang="text">{`Does the model API return structured tool_calls?
├── YES → create_tool_calling_agent        (GPT-4o, Claude, Gemini)
└── NO → Does it reliably output JSON?
         ├── YES → create_structured_chat_agent   (smaller open-source models)
         └── NO → ReAct                            (tiny/basic local models)

Special case: Need state, branching, parallelism, human-in-loop?
         └── Skip all of these → Use LangGraph`}</CodeBlock>

      <Callout kind="intuition" title="They all share the same loop">
        Don't be fooled by the names. All three "agent types" implement the same Reason → Act → Observe loop. The only
        difference is the wire format the LLM uses to say "call this tool." Pick whichever your model speaks best.
      </Callout>

      <CodeBlock file="all_three_same_shape.py">{`# All three follow this exact same pattern:
agent = create_tool_calling_agent(model, tools, prompt)   # just the "brain"
executor = AgentExecutor(agent=agent, tools=tools)         # adds the loop
executor.invoke({"input": "..."})                          # now it actually runs`}</CodeBlock>

      <p>
        Swap <code>create_tool_calling_agent</code> for <code>create_react_agent</code> or <code>create_structured_chat_agent</code> —
        the rest of the code is identical. The agent factory returns a Runnable that produces "next action"; the executor
        wraps it in the loop. <strong>That separation is the whole API surface.</strong>
      </p>
    </section>
  );
}

window.Chapter06 = Chapter06;
