todo_app / src /agents /chatbot.py
MuzammilMax's picture
Upload folder using huggingface_hub
ed5cf78 verified
Raw
History Blame Contribute Delete
4.96 kB
import os
import asyncio
from typing import List, Optional, Dict, Any
from openai import AsyncOpenAI
from agents import Agent, Runner, set_default_openai_client, function_tool, ModelSettings, set_tracing_disabled, OpenAIChatCompletionsModel
from src.config import settings
from src.agents.tools import (
create_task_tool,
list_tasks_tool,
update_task_tool,
delete_task_tool
)
# Configure Gemini via OpenAI SDK (OpenRouter)
GEMINI_API_KEY = settings.GEMINI_API_KEY
client = None
if GEMINI_API_KEY:
# Disable tracing to avoid 401 errors from OpenAI-specific telemetry
set_tracing_disabled(True)
# Set default client for the entire process (using OpenRouter)
client = AsyncOpenAI(
api_key=GEMINI_API_KEY,
base_url="https://openrouter.ai/api/v1",
default_headers={
"HTTP-Referer": "http://localhost:3000",
"X-Title": "MyTodoApp",
}
)
set_default_openai_client(client)
# Set OPENAI_API_KEY to satisfy internal SDK requirements
os.environ["OPENAI_API_KEY"] = GEMINI_API_KEY
class TodoChatbot:
def __init__(self, db, user_id: str):
self.db = db
self.user_id = user_id
# Lock to ensure sequential database access per chatbot instance
self.lock = asyncio.Lock()
# Define local functions that wrap the tools with session, user context, and Lock
async def create_task(title: str, description: Optional[str] = None, status: str = "TODO", priority: str = "MEDIUM") -> str:
"""
Create a new task for the user.
Args:
title: The title of the task.
description: A detailed description of the task.
status: The status of the task (TODO, IN_PROGRESS, DONE).
priority: The priority of the task (LOW, MEDIUM, HIGH).
"""
async with self.lock:
return await create_task_tool(self.db, self.user_id, title, description, status, priority)
async def list_tasks(status: Optional[str] = None) -> str:
"""
List tasks for the user.
Args:
status: Optional filter by status (TODO, IN_PROGRESS, DONE).
"""
async with self.lock:
return await list_tasks_tool(self.db, self.user_id, status)
async def update_task(task_id: str, title: Optional[str] = None, description: Optional[str] = None, status: Optional[str] = None, priority: Optional[str] = None) -> str:
"""
Update an existing task.
Args:
task_id: The UUID of the task to update.
title: New title for the task.
description: New description for the task.
status: New status for the task.
priority: New priority for the task.
"""
async with self.lock:
return await update_task_tool(self.db, self.user_id, task_id, title, description, status, priority)
async def delete_task(task_id: str) -> str:
"""
Delete a task.
Args:
task_id: The UUID of the task to delete.
"""
async with self.lock:
return await delete_task_tool(self.db, self.user_id, task_id)
# Wrap OpenRouter model to bypass SDK prefix validation
gemini_model = OpenAIChatCompletionsModel(
model="google/gemini-2.0-flash-001",
openai_client=client
) if client else "gpt-4o"
self.agent = Agent(
name="TodoBot",
model=gemini_model,
instructions=(
"You are an extremely concise Todo List assistant. "
"Actions: Create, List, Update (Mark Done), Delete. "
"Instructions: "
"1. BE BRIEF. No conversational filler like 'Sure, I can help'. "
"2. When asked to update/complete/delete a task, ALWAYS call 'list_tasks' first to find the ID. "
"3. To mark a task as DONE, use 'update_task' with status='DONE'. "
"4. Confirm actions with a single short sentence: 'Done: Task marked complete.' or 'Task created.' "
"5. Never ask follow-up questions unless the request is truly ambiguous."
),
tools=[
function_tool(create_task),
function_tool(list_tasks),
function_tool(update_task),
function_tool(delete_task)
],
model_settings=ModelSettings(temperature=0.1, max_tokens=1024, parallel_tool_calls=False)
)
async def get_response(self, messages: List[Dict[str, Any]]) -> Any:
"""
Process a list of messages and return the agent's response.
"""
runner = Runner()
result = await runner.run(self.agent, messages)
return result