You are an expert Software Engineer and Python programmer.
Your first task is to read next SRS:

```markdown
# Software Requirements Specification for Dockerfile Analyzer

## 1. Introduction
### 1.1 Purpose
This document specifies the software requirements for the Dockerfile Analyzer, a command-line interface (CLI) tool that utilizes the Google Agent Development Kit (ADK) and a Large Language Model (LLM) to analyze Dockerfiles for potential syntax errors. This SRS covers the entire scope of the CLI tool.

### 1.2 Document Conventions
The following conventions are used throughout this document:

*   `SHALL` indicates a mandatory requirement.
*   `SHOULD` indicates a recommended requirement.
*   `MAY` indicates an optional requirement.
*   Terms are used in accordance with IEEE/ISO/IEC 29148 standards.

### 1.3 Intended Audience and Reading Suggestions
This document is intended for the following audiences:

*   Developers: Responsible for implementing the Dockerfile Analyzer.
*   Testers: Responsible for verifying that the Dockerfile Analyzer meets the specified requirements.
*   Project Managers: Responsible for overseeing the development and deployment of the Dockerfile Analyzer.

The suggested reading sequence is: 1. Introduction, 2. Overall Description, 3. External Interface Requirements, 4. System Features, 5. Other Nonfunctional Requirements, 6. Other Requirements.

### 1.4 Product Scope
The Dockerfile Analyzer is a CLI tool designed to assist developers in identifying potential syntax errors within Dockerfiles. It leverages the Google ADK and Gemini 2.0 Flash LLM to provide intelligent analysis and error detection. The tool aims to improve the quality and reliability of Dockerfiles, reducing build failures and deployment issues.

### 1.5 References
*   IEEE/ISO/IEC 29148:2018 - Requirements Engineering
*   Google Agent Development Kit (ADK) Documentation
*   Gemini 2.0 Flash LLM Documentation

## 2. Overall Description
### 2.1 Product Perspective
The Dockerfile Analyzer is a new, self-contained product designed to improve Dockerfile quality. It is not a part of a larger system, but integrates with the existing development workflow by being a command-line tool.

### 2.2 Product Functions
The Dockerfile Analyzer shall perform the following functions:

*   Accept a Dockerfile as input.
*   Utilize the Google ADK to interface with the Gemini 2.0 Flash LLM.
*   Analyze the Dockerfile content for potential syntax errors.
*   Generate a report of identified errors, including their location and suggested fixes.
*   Provide a confidence level for each identified error.
*   Allow users to specify the level of detail in the error report.

### 2.3 User Classes and Characteristics
The primary user class is developers who create and maintain Dockerfiles. These users typically have experience with Docker and containerization technologies. They possess varying levels of expertise in Dockerfile syntax and best practices. The tool should be usable by both novice and experienced Docker users.

### 2.4 Operating Environment
The Dockerfile Analyzer shall operate in the following environment:

*   Operating System: Any OS that supports Python 3.12 (e.g., Linux, macOS, Windows).
*   Python Version: 3.12
*   Dependencies: Google ADK, required Python libraries for ADK and Gemini 2.0 Flash interaction.
*   Connectivity: Network connectivity required to access the Gemini 2.0 Flash LLM.

### 2.5 Design and Implementation Constraints
The following constraints shall be considered during design and implementation:

*   The Dockerfile Analyzer SHALL be implemented in Python 3.12.
*   The Dockerfile Analyzer SHALL utilize the Google ADK for LLM interaction.
*   The Dockerfile Analyzer SHALL be designed as a command-line interface (CLI) tool.
*   The Dockerfile Analyzer SHALL adhere to security best practices when handling Dockerfile content.
*   The Dockerfile Analyzer SHALL provide informative error messages and usage instructions.
*   Error reporting SHALL be clear, concise and actionable.
```

Then, your second task is create the Dockerfile Analyzer.
You need to create next files:

1. requirements.txt
2. setup.py
3. dockerfile_analyzer.py
4. tests/test_dockerfile_analyzer.py
5. README.md

This is an example of google adk usage:
```python
import asyncio
import os
import logging
from google.adk.agents import Agent, LlmAgent, SequentialAgent
from google.adk.sessions import InMemorySessionService
from google.adk.runners import Runner
from google.genai import types
from dotenv import load_dotenv

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s - %(name)s - %(levelname)s - %(funcName)s - %(message)s",
)
logger = logging.getLogger(__name__)

# Load environment variables
load_dotenv()
GEMINI_API_KEY = os.getenv("GOOGLE_API_KEY")

if not GEMINI_API_KEY:
    logger.error("API key not found. Please set GOOGLE_API_KEY in your .env file.")
    exit()

logger.info(f"API key loaded successfully: {GEMINI_API_KEY}")


# --- 1. Define Constants ---
APP_NAME = "learning_sequential_agents"
USER_ID = "default_user_learning_sequential_agents"
SESSION_ID_TOOL_AGENT = "session_tool_agent_xyz"
MODEL_NAME = "gemini-2.0-flash"
MODEL_CHEAPER_NAME = "gemini-2.0-flash-lite"

# --- 2. Define Schemas ---


# --- 3. Define Tools ---


# --- 4. Configure Agents ---

# Code Writer Agent
# Takes the initial specification (from user query) and writes code.
code_writer_agent = LlmAgent(
    model=MODEL_CHEAPER_NAME,
    name="CodeWriterAgent",
    instruction="""You are a Python Code Generator.
Your task is to *only* write Python code based on the user's request.
Output *only* the complete Python code block, enclosed in triple backticks (```python ... ```).
Do not add any other text before or after the code block.
""",
    description="Writes initial Python code based on a specification.",
    output_key="generated_code",  # Stores output in state['generated_code']
)

# Code Reviewer Agent
# Takes the code generated by the previous agent (read from state) and provides feedback.
code_reviewer_agent = LlmAgent(
    model=MODEL_CHEAPER_NAME,
    name="CodeReviewerAgent",
    description="Reviews code and provides feedback.",
    # Change 3: Improved instruction, correctly using state key injection
    instruction="""You are an expert Python Code Reviewer. 
Your tasks are:
1. Identify the code to review from the user's query.
2. Provide constructive and detailed feedback on the provided code.
3. Use the **Review Criteria** to evaluate the code.
4. Use the **Output** section to provide your feedback.

**Code to Review:**
```python
{generated_code}
    ```

**Review Criteria:**
1.  **Correctness:** Does the code work as intended? Are there logic errors?
2.  **Readability:** Is the code clear and easy to understand? Follows PEP 8 style guidelines?
3.  **Efficiency:** Is the code reasonably efficient? Any obvious performance bottlenecks?
4.  **Edge Cases:** Does the code handle potential edge cases or invalid inputs gracefully?
5.  **Best Practices:** Does the code follow common Python best practices?

**Output:**
Provide your feedback as a concise, bulleted list. Focus on the most important points for improvement.
If the code is excellent and requires no changes, simply state: "No major issues found."
Output *only* the review comments or the "No major issues" statement.
""",
    output_key="review_comments",  # Stores output in state['review_comments']
)


# Code Refactorer Agent
# Takes the original code and the review comments (read from state) and refactors the code.
code_refactorer_agent = LlmAgent(
    name="CodeRefactorerAgent",
    model=MODEL_CHEAPER_NAME,
    # Change 3: Improved instruction, correctly using state key injection
    instruction="""You are a Python Code Refactoring AI.
Your tasks are:
1. Identify the code to refactor from the user's query.
2. Use the **Review Comments** to improve the given Python code based on the provided review comments.
3. Use the **Output** section to provide your refactored code.

**Original Code:**
```python
{generated_code}
```

**Review Comments:**
{review_comments}

**Task:**
Carefully apply the suggestions from the review comments to refactor the original code.
If the review comments state "No major issues found," return the original code unchanged.
Ensure the final code is complete, functional, and includes necessary imports and docstrings.

**Output:**
Output *only* the final, refactored Python code block, enclosed in triple backticks (```python ... ```). 
Do not add any other text before or after the code block.
""",
    description="Refactors code based on review comments.",
    output_key="refactored_code",  # Stores output in state['refactored_code']
)

# Create the SequentialAgent ---
# This agent orchestrates the pipeline by running the sub_agents in order.

# The SequentialAgent is a workflow agent that executes its sub-agents in the order they are specified in the list.
# Use the SequentialAgent when you want the execution to occur in a fixed, strict order.

code_pipeline_agent = SequentialAgent(
    name="CodePipelineAgent",
    sub_agents=[code_writer_agent, code_reviewer_agent, code_refactorer_agent],
    description="Executes a sequence of code writing, reviewing, and refactoring.",
    # The agents will run in the order provided: Writer -> Reviewer -> Refactorer
)

# For ADK tools compatibility, the root agent must be named `root_agent`
root_agent = code_pipeline_agent


# --- 5. Set up Session Management and Runners ---
session_service = InMemorySessionService()

session = session_service.create_session(
    app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID_TOOL_AGENT
)

runner = Runner(
    agent=root_agent,
    app_name=APP_NAME,
    session_service=session_service,
)


# --- 6. Define Agent Interaction Logic ---
async def call_agent_and_print(
    runner_instance: Runner, agent_instance: Agent, session_id: str, query: str
):
    """Sends a query to the specified agent/runner and prints results."""
    logger.info(f"\n>>> User Query: {query}")

    user_content = types.Content(role="user", parts=[types.Part(text=query)])

    final_response_content = "No final response received."
    async for event in runner_instance.run_async(
        user_id=USER_ID, session_id=session_id, new_message=user_content
    ):
        # logger.info(f"Event: {event.type}, Author: {event.author}") # Uncomment for detailed logging
        if event.is_final_response() and event.content and event.content.parts:
            # For output_schema, the content is the JSON string itself
            final_response_content = event.content.parts[0].text

    logger.info(f"<<< Agent Response: {final_response_content}")

    current_session = session_service.get_session(
        app_name=APP_NAME, user_id=USER_ID, session_id=session_id
    )
    # stored_output = current_session.state.get(agent_instance.output_key)
    logger.info(f"Current Session State: {current_session.state}")

    # Write to markdown file
    with open("session_state.md", "w") as f:
        f.write(f"# Session State - {agent_instance.name}\n\n")
        try:
            for key, value in current_session.state.items():
                f.write(f"## {key}\n\n")
                f.write(value)
                f.write("\n")
        except Exception as e:
            logger.error(f"An error occurred: {e}")
        f.write("\n" + "-" * 30 + "\n")


# --- 7. Run Interactions ---
async def run_agents():
    logger.info("\n--- Testing Agents ---")

    await call_agent_and_print(
        runner,
        root_agent,
        SESSION_ID_TOOL_AGENT,
        # "Write a Python function that takes a city (str) and returns the current time in that city using ZoneInfo.",
        "Write a Python script to undersand the Google ADK framework.",
    )


if __name__ == "__main__":
    try:
        asyncio.run(run_agents())
    except Exception as e:
        logger.error(f"An error occurred: {e}")
```