Skip to content

Commit 1a7b7e6

Browse files
authored
Merge pull request #5 from debuggerone/examples
Examples
2 parents 971936d + 2858ac6 commit 1a7b7e6

15 files changed

+281
-254
lines changed

examples/filter_list_example.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import asyncio
2+
from core.filter_list_agent import FilterListAgent
3+
4+
async def run_filter_list_example():
5+
goal = "Remove items that are unhealthy snacks."
6+
items_to_filter = [
7+
"Apple",
8+
"Chocolate bar",
9+
"Carrot",
10+
"Chips",
11+
"Orange"
12+
]
13+
14+
agent = FilterListAgent(goal=goal, items_to_filter=items_to_filter)
15+
filtered_results = await agent.filter()
16+
17+
print("Original list:", items_to_filter)
18+
print("Filtered results:")
19+
for result in filtered_results:
20+
print(result)
21+
22+
if __name__ == "__main__":
23+
asyncio.run(run_filter_list_example())

examples/sort_list_example.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import asyncio
2+
from core.sort_list_agent import SortListAgent
3+
4+
async def run_sort_list_example():
5+
# Sample input list
6+
items_to_sort = [
7+
"Apple", "Orange", "Banana", "Grape", "Pineapple"
8+
]
9+
10+
# Define a goal for sorting (this will influence the OpenAI model's decision)
11+
goal = "Sort the fruits alphabetically."
12+
13+
# Create the sorting agent
14+
agent = SortListAgent(goal=goal, list_to_sort=items_to_sort, log_explanations=True)
15+
16+
# Execute the sorting process
17+
sorted_list = await agent.sort()
18+
19+
# Output the result
20+
print("Original list:", items_to_sort)
21+
print("Sorted list:", sorted_list)
22+
23+
# Run the example
24+
if __name__ == "__main__":
25+
asyncio.run(run_sort_list_example())

install.py

Lines changed: 3 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import sqlite3
21
import os
32
import json
43
import argparse
@@ -9,94 +8,29 @@ def create_settings(ci_mode=False):
98
if ci_mode:
109
# Use default values for CI
1110
api_key = "sk-test-key"
12-
tier = "tier-4"
1311
log_path = './var/logs/error.log'
14-
database_path = './var/data/agents.db'
12+
debug = False
1513
else:
1614
# Prompt user for settings
1715
api_key = input('Enter your OpenAI API key: ')
18-
tier = input('Enter your OpenAI tier level (e.g., tier-1): ')
1916
log_path = input('Enter the log directory path [default: ./var/logs/error.log]: ') or './var/logs/error.log'
20-
database_path = input('Enter the database path [default: ./var/data/agents.db]: ') or './var/data/agents.db'
17+
debug = input('Enable debug mode? [y/n]: ').lower() == 'y'
2118

2219
# Save settings to JSON file
2320
settings = {
2421
'openai_api_key': api_key,
25-
'tier': tier,
2622
'log_path': log_path,
27-
'database_path': database_path
23+
'debug': debug
2824
}
2925
os.makedirs('./config', exist_ok=True)
3026
with open('./config/settings.json', 'w') as f:
3127
json.dump(settings, f, indent=4)
3228
print('Settings saved to config/settings.json')
3329

3430

35-
# Function to create the database structure
36-
37-
def create_database(db_path):
38-
os.makedirs(os.path.dirname(db_path), exist_ok=True)
39-
conn = sqlite3.connect(db_path)
40-
c = conn.cursor()
41-
42-
# Create tables
43-
c.execute('''CREATE TABLE IF NOT EXISTS models (
44-
id INTEGER PRIMARY KEY,
45-
model TEXT NOT NULL,
46-
price_per_prompt_token REAL NOT NULL,
47-
price_per_completion_token REAL NOT NULL)''')
48-
49-
c.execute('''CREATE TABLE IF NOT EXISTS rate_limits (
50-
id INTEGER PRIMARY KEY,
51-
model TEXT NOT NULL,
52-
tier TEXT NOT NULL,
53-
rpm_limit INTEGER NOT NULL,
54-
tpm_limit INTEGER NOT NULL,
55-
rpd_limit INTEGER NOT NULL)''')
56-
57-
c.execute('''CREATE TABLE IF NOT EXISTS api_usage (
58-
id INTEGER PRIMARY KEY,
59-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
60-
session_id TEXT NOT NULL,
61-
model TEXT NOT NULL,
62-
prompt_tokens INTEGER NOT NULL,
63-
completion_tokens INTEGER NOT NULL,
64-
total_tokens INTEGER NOT NULL,
65-
price_per_prompt_token REAL NOT NULL,
66-
price_per_completion_token REAL NOT NULL,
67-
total_cost REAL NOT NULL)''')
68-
69-
c.execute('''CREATE TABLE IF NOT EXISTS chat_sessions (
70-
id INTEGER PRIMARY KEY,
71-
session_id TEXT NOT NULL,
72-
start_time DATETIME DEFAULT CURRENT_TIMESTAMP,
73-
end_time DATETIME)''')
74-
75-
c.execute('''CREATE TABLE IF NOT EXISTS chats (
76-
id INTEGER PRIMARY KEY,
77-
session_id TEXT NOT NULL,
78-
chat_id TEXT NOT NULL,
79-
message TEXT NOT NULL,
80-
role TEXT NOT NULL,
81-
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)''')
82-
83-
# Insert default models and rate limits
84-
c.execute("INSERT INTO models (model, price_per_prompt_token, price_per_completion_token) VALUES ('gpt-4o-mini', 0.03, 0.06)")
85-
c.execute("INSERT INTO rate_limits (model, tier, rpm_limit, tpm_limit, rpd_limit) VALUES ('gpt-4o-mini', 'tier-1', 60, 50000, 1000)")
86-
87-
conn.commit()
88-
conn.close()
89-
print(f"Database created at {db_path}")
90-
91-
9231
if __name__ == '__main__':
9332
parser = argparse.ArgumentParser(description='Setup script for installation.')
9433
parser.add_argument('--ci', action='store_true', help='Use default values for CI without prompting.')
9534
args = parser.parse_args()
9635

9736
create_settings(ci_mode=args.ci)
98-
99-
with open('./config/settings.json', 'r') as f:
100-
settings = json.load(f)
101-
102-
create_database(settings['database_path'])

requirements.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ flake8
1717
tiktoken
1818
anyio
1919
trio
20+
openai
21+
jsonschema

src/core/database.py

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/core/filter_list_agent.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import asyncio
2+
import json
3+
import jsonschema
4+
from typing import List, Dict
5+
from .openai_api import OpenAIClient
6+
7+
class FilterListAgent:
8+
def __init__(self, goal: str, items_to_filter: List[str], max_tokens: int = 500, temperature: float = 0.0):
9+
self.goal = goal
10+
self.items = items_to_filter
11+
self.max_tokens = max_tokens
12+
self.temperature = temperature
13+
self.openai_client = OpenAIClient()
14+
15+
# JSON schema for validation
16+
schema = {
17+
"type": "object",
18+
"properties": {
19+
"explanation": {"type": "string"},
20+
"remove_item": {"type": "boolean"}
21+
},
22+
"required": ["explanation", "remove_item"]
23+
}
24+
25+
async def filter(self) -> List[Dict]:
26+
return await self.filter_list(self.items)
27+
28+
async def filter_list(self, items: List[str]) -> List[Dict]:
29+
# System prompt with multi-shot examples to guide the model
30+
system_prompt = (
31+
"You are an assistant tasked with filtering a list of items. The goal is: "
32+
f"{self.goal}. For each item, decide if it should be removed based on whether it is a healthy snack.\n"
33+
"Respond in the following structured format:\n\n"
34+
"Example:\n"
35+
"{\"explanation\": \"The apple is a healthy snack option, as it is low in calories...\",\n"
36+
" \"remove_item\": false}\n\n"
37+
"Example:\n"
38+
"{\"explanation\": \"A chocolate bar is generally considered an unhealthy snack...\",\n"
39+
" \"remove_item\": true}\n\n"
40+
)
41+
42+
tasks = []
43+
for index, item in enumerate(items):
44+
user_prompt = f"Item {index+1}: {item}. Should it be removed? Answer with explanation and 'remove_item': true/false."
45+
tasks.append(self.filter_item(system_prompt, user_prompt))
46+
47+
# Run all tasks in parallel
48+
results = await asyncio.gather(*tasks)
49+
50+
# Show the final list of items that were kept
51+
filtered_items = [self.items[i] for i, result in enumerate(results) if not result.get('remove_item', False)]
52+
print("\nFinal Filtered List:", filtered_items)
53+
54+
return results
55+
56+
async def filter_item(self, system_prompt: str, user_prompt: str) -> Dict:
57+
response = await self.openai_client.complete_chat([
58+
{"role": "system", "content": system_prompt},
59+
{"role": "user", "content": user_prompt}
60+
], max_tokens=self.max_tokens)
61+
62+
return await self.process_response(response, system_prompt, user_prompt)
63+
64+
async def process_response(self, response: str, system_prompt: str, user_prompt: str, retry: bool = True) -> Dict:
65+
try:
66+
# Parse the response as JSON
67+
result = json.loads(response)
68+
# Validate against the schema
69+
jsonschema.validate(instance=result, schema=self.schema)
70+
return result
71+
except (json.JSONDecodeError, jsonschema.ValidationError) as e:
72+
if retry:
73+
# Retry once if validation fails
74+
return await self.filter_item(system_prompt, user_prompt)
75+
else:
76+
return {"error": f"Failed to parse response after retry: {str(e)}", "response": response, "item": user_prompt}

src/core/logging.py

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,47 @@
11
import logging
2+
import http.client
23
import json
34
import os
45

5-
66
class Logger:
77
def __init__(self, settings_path="../config/settings.json"):
88
self.settings = self.load_settings(settings_path)
99
self.log_path = self.settings["log_path"]
1010
os.makedirs(os.path.dirname(self.log_path), exist_ok=True)
11-
logging.basicConfig(
12-
filename=self.log_path,
13-
level=logging.INFO,
14-
format="%(asctime)s - %(levelname)s - %(message)s",
15-
)
11+
12+
# Create a logger instance
13+
self.logger = logging.getLogger("AgentMLogger")
14+
self.logger.setLevel(logging.DEBUG if self.settings.get("debug", False) else logging.INFO)
15+
16+
# File handler for logging to a file
17+
file_handler = logging.FileHandler(self.log_path)
18+
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
19+
self.logger.addHandler(file_handler)
20+
21+
# Console handler for output to the console
22+
console_handler = logging.StreamHandler()
23+
console_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
24+
self.logger.addHandler(console_handler)
25+
26+
# Enable HTTP-level logging if debug is enabled
27+
if self.settings.get("debug", False):
28+
self.enable_http_debug()
1629

1730
def load_settings(self, settings_path):
18-
try:
19-
with open(settings_path, "r") as f:
20-
return json.load(f)
21-
except FileNotFoundError:
22-
raise Exception(f"Settings file not found at {settings_path}")
23-
except KeyError as e:
24-
raise Exception(f"Missing key in settings: {e}")
31+
if not os.path.exists(settings_path):
32+
raise FileNotFoundError(f"Settings file not found at {settings_path}")
33+
with open(settings_path, "r") as f:
34+
return json.load(f)
35+
36+
def enable_http_debug(self):
37+
"""Enable HTTP-level logging for API communication."""
38+
http.client.HTTPConnection.debuglevel = 1
39+
logging.getLogger("http.client").setLevel(logging.DEBUG)
40+
logging.getLogger("http.client").propagate = True
2541

2642
def info(self, message):
27-
logging.info(message)
43+
self.logger.info(message)
2844

2945
def error(self, message):
30-
logging.error(message)
46+
self.logger.error(message)
47+
print(f"ERROR: {message}")

0 commit comments

Comments
 (0)