{
  "license": "CC BY 4.0",
  "licenseUrl": "https://creativecommons.org/licenses/by/4.0/",
  "recipe": {
    "slug": "agent-tool-loop-detection",
    "title": "Detect Repeating AI Agent Tool Loops",
    "testedWith": "Apache DataFusion 45.2.0",
    "lastReviewed": "2026-07-27"
  },
  "contract": {
    "tableName": "agent_tool_calls",
    "schema": [
      {
        "name": "timestamp_utc",
        "type": "Timestamp",
        "description": "Tool-call completion time."
      },
      {
        "name": "run_id",
        "type": "Utf8",
        "description": "Stable identifier for one agent run."
      },
      {
        "name": "agent_name",
        "type": "Utf8",
        "description": "Agent workflow name."
      },
      {
        "name": "tool_name",
        "type": "Utf8",
        "description": "Called tool name."
      },
      {
        "name": "status",
        "type": "Utf8",
        "description": "Tool-call outcome."
      },
      {
        "name": "estimated_cost_usd",
        "type": "Float64",
        "description": "Cost attributed to the step when available."
      }
    ]
  },
  "query": "SELECT\n  run_id,\n  agent_name,\n  COUNT(*) AS tool_calls,\n  COUNT(DISTINCT tool_name) AS distinct_tools,\n  SUM(CASE WHEN status = 'failed' THEN 1 ELSE 0 END) AS failed_calls,\n  SUM(estimated_cost_usd) AS tool_loop_cost_usd,\n  MIN(timestamp_utc) AS first_call_at,\n  MAX(timestamp_utc) AS last_call_at\nFROM agent_tool_calls\nWHERE timestamp_utc >= now() - INTERVAL '24 hours'\nGROUP BY run_id, agent_name\nHAVING COUNT(*) >= 8\n  AND COUNT(DISTINCT tool_name) <= 2\nORDER BY tool_calls DESC, tool_loop_cost_usd DESC\nLIMIT 100;",
  "fixtureKind": "schema-example",
  "inputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "run_id": "run_id_example_1",
      "agent_name": "agent_name_example_1",
      "tool_name": "tool_name_example_1",
      "status": "success",
      "estimated_cost_usd": 0.014
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "run_id": "run_id_example_2",
      "agent_name": "agent_name_example_2",
      "tool_name": "tool_name_example_2",
      "status": "failed",
      "estimated_cost_usd": 0.052
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "run_id": "run_id_example_3",
      "agent_name": "agent_name_example_3",
      "tool_name": "tool_name_example_3",
      "status": "success",
      "estimated_cost_usd": 0.021
    }
  ],
  "illustrativeInputRows": [
    {
      "timestamp_utc": "2026-07-28T10:00:00Z",
      "run_id": "run_id_example_1",
      "agent_name": "agent_name_example_1",
      "tool_name": "tool_name_example_1",
      "status": "success",
      "estimated_cost_usd": 0.014
    },
    {
      "timestamp_utc": "2026-07-28T11:00:00Z",
      "run_id": "run_id_example_2",
      "agent_name": "agent_name_example_2",
      "tool_name": "tool_name_example_2",
      "status": "failed",
      "estimated_cost_usd": 0.052
    },
    {
      "timestamp_utc": "2026-07-28T12:00:00Z",
      "run_id": "run_id_example_3",
      "agent_name": "agent_name_example_3",
      "tool_name": "tool_name_example_3",
      "status": "success",
      "estimated_cost_usd": 0.021
    }
  ],
  "expectedOutput": {
    "columns": [
      "run_id",
      "agent_name",
      "tool_calls",
      "distinct_tools",
      "failed_calls",
      "tool_loop_cost_usd",
      "first_call_at",
      "last_call_at"
    ],
    "rows": [
      {
        "run_id": "run_9021",
        "agent_name": "billing_reconciler",
        "tool_calls": 17,
        "distinct_tools": 2,
        "failed_calls": 8,
        "tool_loop_cost_usd": 0.84,
        "first_call_at": "12:02:11",
        "last_call_at": "12:06:48"
      },
      {
        "run_id": "run_9154",
        "agent_name": "support_agent",
        "tool_calls": 11,
        "distinct_tools": 1,
        "failed_calls": 0,
        "tool_loop_cost_usd": 0.31,
        "first_call_at": "12:44:10",
        "last_call_at": "12:45:32"
      }
    ]
  },
  "notes": [
    "The compact input rows demonstrate field names and JSON types; they are not claimed to generate the displayed aggregate by themselves.",
    "The expected output is deterministic synthetic review data for the documented output shape.",
    "Adapt time windows, thresholds, identities, and business definitions before operational use."
  ]
}