Skip to content

Commit 174b474

Browse files
committed
feat: Initial commit of the reflection agent service
0 parents  commit 174b474

23 files changed

+541
-0
lines changed

.github/workflows/ci.yml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# File: .github/workflows/ci.yml
2+
name: Code Quality and Tests
3+
4+
# This workflow runs on every push to the main branch
5+
on:
6+
push:
7+
branches: [ "main" ]
8+
pull_request:
9+
branches: [ "main" ]
10+
11+
jobs:
12+
build-and-test:
13+
# The type of runner that the job will run on
14+
runs-on: ubuntu-latest
15+
16+
steps:
17+
# Step 1: Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
18+
- name: Checkout code
19+
uses: actions/checkout@v4
20+
21+
# Step 2: Set up a specific version of Python
22+
- name: Set up Python
23+
uses: actions/setup-python@v5
24+
with:
25+
python-version: '3.12'
26+
27+
# Step 3: Install dependencies from our requirements.txt
28+
- name: Install dependencies
29+
run: |
30+
python -m pip install --upgrade pip
31+
pip install -r requirements.txt
32+
pip install -e .
33+
34+
# Step 4: Lint the code with Ruff for style and quality checks
35+
- name: Lint with Ruff
36+
run: |
37+
ruff check .
38+
39+
# Step 5: Run the unit tests with Pytest
40+
- name: Test with Pytest
41+
run: |
42+
pytest

.gitinore

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# --- Secrets ---
2+
# The golden rule: never commit secrets.
3+
.env
4+
5+
# --- Python Cache & Compiled Files ---
6+
# These are generated automatically by the Python interpreter.
7+
__pycache__/
8+
*.pyc
9+
10+
# --- Python Build & Installation Artifacts ---
11+
# Generated by setuptools/pip when installing in editable mode.
12+
*.egg-info/
13+
build/
14+
dist/
15+
16+
# --- Testing Artifacts ---
17+
# Cache generated by pytest to speed up tests.
18+
.pytest_cache/
19+
20+
# --- IDE/Editor Specific ---
21+
# VSCode specific files
22+
.vscode/

Dockerfile

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Stage 1: Use an official lightweight Python image as a parent image
2+
FROM python:3.12-slim
3+
4+
# Set the working directory inside the container
5+
WORKDIR /app
6+
7+
# Copy the file with dependencies first
8+
COPY requirements.txt .
9+
10+
# Install the dependencies
11+
# --no-cache-dir makes the image smaller
12+
RUN pip install --no-cache-dir -r requirements.txt
13+
14+
# Copy the rest of application code into the container
15+
COPY . .
16+
17+
# Tell Docker that the container will listen on port 8001
18+
EXPOSE 8001
19+
20+
# The command to run application when the container starts
21+
# Use 0.0.0.0 to make the server accessible from outside the container
22+
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8001"]

__pycache__/main.cpython-312.pyc

3.15 KB
Binary file not shown.
2.65 KB
Binary file not shown.

lab_reflection_agent.ipynb

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "75d3bee5",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": [
10+
"# We install the necessary libraries directly from the notebook.\n",
11+
"# The '!' allows us to run shell commands.\n",
12+
"!pip install openai python-dotenv"
13+
]
14+
},
15+
{
16+
"cell_type": "code",
17+
"execution_count": null,
18+
"id": "ee51e92d",
19+
"metadata": {},
20+
"outputs": [],
21+
"source": [
22+
"import os\n",
23+
"from dotenv import load_dotenv\n",
24+
"\n",
25+
"# Import our custom agent class\n",
26+
"from reflection_pattern_agent.reflection_agent import ReflectionAgent\n",
27+
"\n",
28+
"# Load environment variables from the .env file\n",
29+
"# This is where we securely load our OPENAI_API_KEY\n",
30+
"load_dotenv()\n",
31+
"\n",
32+
"print(\"Libraries and agent class imported successfully.\")"
33+
]
34+
},
35+
{
36+
"cell_type": "code",
37+
"execution_count": null,
38+
"id": "9e2757f1",
39+
"metadata": {},
40+
"outputs": [],
41+
"source": [
42+
"# 1. Instantiate the agent\n",
43+
"# This will automatically pick up the API key from the environment\n",
44+
"agent = ReflectionAgent()\n",
45+
"\n",
46+
"# 2. Define a simple prompt to test the generation\n",
47+
"test_prompt = \"Write a short, engaging tweet about the importance of MLOps.\"\n",
48+
"\n",
49+
"# 3. Call the generate method\n",
50+
"print(\"--- Calling the generate method... ---\")\n",
51+
"initial_draft = agent.generate(prompt=test_prompt)\n",
52+
"\n",
53+
"# 4. Print the result\n",
54+
"print(\"\\n--- Initial Draft Generated ---\")\n",
55+
"print(initial_draft)"
56+
]
57+
},
58+
{
59+
"cell_type": "code",
60+
"execution_count": null,
61+
"id": "a42e570b",
62+
"metadata": {},
63+
"outputs": [],
64+
"source": [
65+
"# --- Full Cycle Integration Test ---\n",
66+
"\n",
67+
"# 1. Define a more complex task where reflection can make a real difference.\n",
68+
"complex_prompt = \"\"\"\n",
69+
"Write a short paragraph for a LinkedIn post announcing a new feature\n",
70+
"for our project management tool. The feature is an AI-powered assistant\n",
71+
"that automatically suggests the next task for a user based on their\n",
72+
"project's progress and priorities. Mention the key benefit:\n",
73+
"it helps reduce decision fatigue for team leads.\n",
74+
"\"\"\"\n",
75+
"\n",
76+
"# 2. Execute the full run cycle\n",
77+
"initial_draft, reflections, final_output = agent.run(prompt=complex_prompt)\n",
78+
"\n",
79+
"# 3. Analyze the results\n",
80+
"print(\"\\n\" + \"=\"*50)\n",
81+
"print(\"INITIAL DRAFT\")\n",
82+
"print(\"=\"*50)\n",
83+
"print(initial_draft)\n",
84+
"\n",
85+
"print(\"\\n\" + \"=\"*50)\n",
86+
"print(\"REFLECTIONS\")\n",
87+
"print(\"=\"*50)\n",
88+
"# Print reflections as a bulleted list\n",
89+
"for r in reflections:\n",
90+
" print(f\"- {r}\")\n",
91+
"\n",
92+
"print(\"\\n\" + \"=\"*50)\n",
93+
"print(\"FINAL REFINED OUTPUT\")\n",
94+
"print(\"=\"*50)\n",
95+
"print(final_output)"
96+
]
97+
}
98+
],
99+
"metadata": {
100+
"kernelspec": {
101+
"display_name": "reflection_agent",
102+
"language": "python",
103+
"name": "python3"
104+
},
105+
"language_info": {
106+
"codemirror_mode": {
107+
"name": "ipython",
108+
"version": 3
109+
},
110+
"file_extension": ".py",
111+
"mimetype": "text/x-python",
112+
"name": "python",
113+
"nbconvert_exporter": "python",
114+
"pygments_lexer": "ipython3",
115+
"version": "3.12.3"
116+
}
117+
},
118+
"nbformat": 4,
119+
"nbformat_minor": 5
120+
}

main.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import logging
2+
from dotenv import load_dotenv
3+
from fastapi import FastAPI, HTTPException
4+
from pydantic import BaseModel, Field
5+
from typing import List
6+
7+
# Load environment variables from a .env file
8+
load_dotenv()
9+
10+
# Import core logic
11+
from reflection_pattern_agent.reflection_agent import ReflectionAgent
12+
13+
# Set up logging
14+
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
15+
logger = logging.getLogger(__name__)
16+
17+
# --- The API Contract (Pydantic Models) ---
18+
19+
class RunRequest(BaseModel):
20+
prompt: str = Field(
21+
...,
22+
description="The initial prompt for the agent to process.",
23+
example="Write a tweet about the future of AI agents."
24+
)
25+
26+
class RunResponse(BaseModel):
27+
initial_draft: str
28+
reflections: List[str]
29+
final_output: str
30+
31+
# --- FastAPI Application Setup ---
32+
app = FastAPI(
33+
title="Reflection Agent Service",
34+
description="An API to access an AI agent that uses the reflection pattern to improve its output.",
35+
version="1.0.0"
36+
)
37+
38+
# --- API Endpoints ---
39+
40+
# Basic health check endpoint
41+
@app.get("/health", tags=["Monitoring"])
42+
def health_check():
43+
"""Checks if the service is running."""
44+
return {"status": "ok"}
45+
46+
@app.post("/run", response_model=RunResponse, tags=["Agent Logic"])
47+
def execute_agent_run(request: RunRequest):
48+
"""
49+
Executes the full generate-reflect-generate cycle of the agent.
50+
"""
51+
try:
52+
logger.info(f"Received request for prompt: '{request.prompt[:50]}...'") # Log de início
53+
agent = ReflectionAgent()
54+
initial_draft, reflections, final_output = agent.run(request.prompt)
55+
56+
if initial_draft is None:
57+
logger.error("Agent failed to generate an initial draft.")
58+
raise HTTPException(status_code=500, detail="Agent failed to generate an initial draft.")
59+
60+
logger.info("Successfully completed agent run.") # Log de sucesso
61+
return RunResponse(
62+
initial_draft=initial_draft,
63+
reflections=reflections,
64+
final_output=final_output
65+
)
66+
except Exception as e:
67+
# ESTA É A MUDANÇA MAIS IMPORTANTE
68+
logger.exception("An unhandled exception occurred during agent run.")
69+
raise HTTPException(status_code=500, detail=f"An internal error occurred: {str(e)}")

pyproject.toml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[project]
2+
name = "reflection_pattern_agent"
3+
version = "0.1.0"
4+
authors = [
5+
{ name="Priscila Santos", email="priscila.olimpia@gmail.com" },
6+
]
7+
description = "An agentic pattern for self-reflection and output improvement."
8+
readme = "README.md" # TO DO add a README file
9+
requires-python = ">=3.9"
10+
classifiers = [
11+
"Programming Language :: Python :: 3",
12+
"License :: OSI Approved :: MIT License",
13+
"Operating System :: OS Independent",
14+
]
15+
16+
[tool.setuptools.packages.find]
17+
where = ["."]
18+
include = ["reflection_pattern_agent*"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Metadata-Version: 2.4
2+
Name: reflection_pattern_agent
3+
Version: 0.1.0
4+
Summary: An agentic pattern for self-reflection and output improvement.
5+
Author-email: Seu Nome <seu@email.com>
6+
Classifier: Programming Language :: Python :: 3
7+
Classifier: License :: OSI Approved :: MIT License
8+
Classifier: Operating System :: OS Independent
9+
Requires-Python: >=3.9
10+
Description-Content-Type: text/markdown
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
pyproject.toml
2+
reflection_pattern_agent/__init__.py
3+
reflection_pattern_agent/reflection_agent.py
4+
reflection_pattern_agent.egg-info/PKG-INFO
5+
reflection_pattern_agent.egg-info/SOURCES.txt
6+
reflection_pattern_agent.egg-info/dependency_links.txt
7+
reflection_pattern_agent.egg-info/top_level.txt
8+
tests/test_reflection_agent.py

0 commit comments

Comments
 (0)