umar-30 commited on
Commit
409c8b3
·
verified ·
1 Parent(s): b9f5113

update the code

Browse files
Files changed (1) hide show
  1. app/agent/task_agent.py +213 -233
app/agent/task_agent.py CHANGED
@@ -1,123 +1,125 @@
1
- """
2
- Task Agent implementation using OpenAI API directly with OpenRouter.
3
-
4
- Provides an AI agent that maps natural language to MCP tools for task management.
5
- """
6
- import json
7
- from typing import Any
8
-
9
- from openai import AsyncOpenAI
10
-
11
- from .prompts import SYSTEM_PROMPT
12
- from ..mcp import tools as mcp_tools
13
-
14
- # Tool definitions for OpenAI function calling
15
- TOOLS = [
16
- {
17
- "type": "function",
18
- "function": {
19
- "name": "add_task",
20
- "description": "Create a new task for a user",
21
- "parameters": {
22
- "type": "object",
23
- "properties": {
24
- "user_id": {"type": "string", "description": "The user's unique identifier"},
25
- "title": {"type": "string", "description": "The task title"},
26
- "description": {"type": "string", "description": "Optional task description"}
27
- },
28
- "required": ["user_id", "title"]
29
- }
30
- }
31
- },
32
- {
33
- "type": "function",
34
- "function": {
35
- "name": "list_tasks",
36
- "description": "Get all tasks for a user",
37
- "parameters": {
38
- "type": "object",
39
- "properties": {
40
- "user_id": {"type": "string", "description": "The user's unique identifier"}
41
- },
42
- "required": ["user_id"]
43
- }
44
- }
45
- },
46
- {
47
- "type": "function",
48
- "function": {
49
- "name": "complete_task",
50
- "description": "Mark a task as completed. IMPORTANT: You must first call list_tasks to get the task UUID, then use that UUID here.",
51
- "parameters": {
52
- "type": "object",
53
- "properties": {
54
- "user_id": {"type": "string", "description": "The user's unique identifier"},
55
- "task_id": {"type": "string", "description": "The task's UUID (e.g., 'd18627f4-73ff-4450-943e-451c24962de0'). NOT the task title!"}
56
- },
57
- "required": ["user_id", "task_id"]
58
- }
59
- }
60
- },
61
- {
62
- "type": "function",
63
- "function": {
64
- "name": "update_task",
65
- "description": "Update a task's title or description",
66
- "parameters": {
67
- "type": "object",
68
- "properties": {
69
- "user_id": {"type": "string", "description": "The user's unique identifier"},
70
- "task_id": {"type": "string", "description": "The task's unique identifier (UUID)"},
71
- "title": {"type": "string", "description": "New task title"},
72
- "description": {"type": "string", "description": "New task description"}
73
- },
74
- "required": ["user_id", "task_id"]
75
- }
76
- }
77
- },
78
- {
79
- "type": "function",
80
- "function": {
81
- "name": "delete_task",
82
- "description": "Permanently delete a task",
83
- "parameters": {
84
- "type": "object",
85
- "properties": {
86
- "user_id": {"type": "string", "description": "The user's unique identifier"},
87
- "task_id": {"type": "string", "description": "The task's unique identifier (UUID)"}
88
- },
89
- "required": ["user_id", "task_id"]
90
- }
91
- }
92
- }
93
- ]
94
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
96
- def execute_tool(name: str, arguments: dict) -> Any:
97
- """Execute a tool by name with given arguments."""
98
- if name == "add_task":
99
- return mcp_tools.add_task(
100
- arguments["user_id"],
101
- arguments["title"],
102
- arguments.get("description")
103
- )
104
- elif name == "list_tasks":
105
- return mcp_tools.list_tasks(arguments["user_id"])
106
- elif name == "complete_task":
107
- return mcp_tools.complete_task(arguments["user_id"], arguments["task_id"])
108
- elif name == "update_task":
109
- return mcp_tools.update_task(
110
- arguments["user_id"],
111
- arguments["task_id"],
112
- arguments.get("title"),
113
- arguments.get("description")
114
- )
115
- elif name == "delete_task":
116
- return mcp_tools.delete_task(arguments["user_id"], arguments["task_id"])
117
- else:
118
- return {"error": f"Unknown tool: {name}"}
119
 
120
- class TaskAgent:
121
  """
122
  AI agent for task management via natural language.
123
  Uses OpenAI API directly for reliable tool/function calling support.
@@ -140,122 +142,100 @@ def execute_tool(name: str, arguments: dict) -> Any:
140
  )
141
  # Use gpt-4o-mini for fast, reliable tool calling
142
  self.model = model or "gpt-4o-mini"
143
-
144
- # class TaskAgent:
145
- # """
146
- # AI agent for task management via natural language.
147
- # Uses OpenAI-compatible API (OpenRouter) with function calling.
148
- # """
149
-
150
- # def __init__(self, model: str | None = None):
151
- # """
152
- # Initialize the TaskAgent.
153
-
154
- # Args:
155
- # model: Model to use (default: from config)
156
- # """
157
- # from ..config import get_settings
158
- # settings = get_settings()
159
-
160
- # self.client = AsyncOpenAI(
161
- # api_key=settings.openrouter_api_key,
162
- # base_url=settings.openrouter_base_url,
163
- # )
164
- # self.model = model or settings.openrouter_model
165
-
166
- async def run(
167
- self,
168
- message: str,
169
- user_id: str,
170
- context: dict[str, Any] | None = None
171
- ) -> dict[str, Any]:
172
- """
173
- Process a user message and return the agent's response.
174
-
175
- Args:
176
- message: User's natural language message
177
- user_id: User identifier for tool calls
178
- context: Optional additional context
179
-
180
- Returns:
181
- dict with response and tool_calls
182
- """
183
- # Build messages
184
- messages = [
185
- {"role": "system", "content": SYSTEM_PROMPT + f"\n\nCurrent User ID: {user_id}"}
186
- ]
187
-
188
- # Add conversation history if available
189
- if context and context.get("conversation_history"):
190
- for msg in context["conversation_history"][-5:]:
191
- messages.append({
192
- "role": msg["role"],
193
- "content": msg["content"]
194
- })
195
-
196
- # Add current user message
197
- messages.append({"role": "user", "content": message})
198
 
199
- tool_calls_made = []
200
-
201
- # Call the model
202
- response = await self.client.chat.completions.create(
203
- model=self.model,
204
- messages=messages,
205
- tools=TOOLS,
206
- tool_choice="auto",
207
- )
208
-
209
- assistant_message = response.choices[0].message
210
-
211
- # Handle tool calls if any
212
- while assistant_message.tool_calls:
213
- # Add assistant message with tool calls
214
- messages.append(assistant_message)
215
-
216
- # Execute each tool call
217
- for tool_call in assistant_message.tool_calls:
218
- function_name = tool_call.function.name
219
- arguments = json.loads(tool_call.function.arguments)
220
-
221
- # Inject user_id if not provided
222
- if "user_id" not in arguments:
223
- arguments["user_id"] = user_id
224
-
225
- # Execute the tool
226
- result = execute_tool(function_name, arguments)
227
-
228
- tool_calls_made.append({
229
- "name": function_name,
230
- "arguments": arguments,
231
- "result": result
232
- })
233
-
234
- # Add tool result to messages
235
- messages.append({
236
- "role": "tool",
237
- "tool_call_id": tool_call.id,
238
- "content": json.dumps(result)
239
- })
240
-
241
- # Get next response
242
- response = await self.client.chat.completions.create(
243
- model=self.model,
244
- messages=messages,
245
- tools=TOOLS,
246
- tool_choice="auto",
247
- )
248
- assistant_message = response.choices[0].message
249
-
250
- # Get final text response
251
- response_text = assistant_message.content or ""
252
 
253
- return {
254
- "response": response_text,
255
- "tool_calls": tool_calls_made
256
- }
257
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
258
 
259
- def create_task_agent(model: str | None = None) -> TaskAgent:
260
- """Factory function to create a TaskAgent instance."""
261
- return TaskAgent(model=model)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Task Agent implementation using OpenAI API directly.
2
+
3
+ Provides an AI agent that maps natural language to MCP tools for task management.
4
+ Uses OpenAI's gpt-4o-mini for reliable function calling/tool use support.
5
+ """
6
+ import json
7
+ from typing import Any
8
+
9
+ from openai import AsyncOpenAI
10
+
11
+ from .prompts import SYSTEM_PROMPT
12
+ from ..mcp import tools as mcp_tools
13
+
14
+ # Tool definitions for OpenAI function calling
15
+ TOOLS = [
16
+ {
17
+ "type": "function",
18
+ "function": {
19
+ "name": "add_task",
20
+ "description": "Create a new task for a user",
21
+ "parameters": {
22
+ "type": "object",
23
+ "properties": {
24
+ "user_id": {"type": "string", "description": "The user's unique identifier"},
25
+ "title": {"type": "string", "description": "The task title"},
26
+ "description": {"type": "string", "description": "Optional task description"}
27
+ },
28
+ "required": ["user_id", "title"]
29
+ }
30
+ }
31
+ },
32
+ {
33
+ "type": "function",
34
+ "function": {
35
+ "name": "list_tasks",
36
+ "description": "Get all tasks for a user",
37
+ "parameters": {
38
+ "type": "object",
39
+ "properties": {
40
+ "user_id": {"type": "string", "description": "The user's unique identifier"}
41
+ },
42
+ "required": ["user_id"]
43
+ }
44
+ }
45
+ },
46
+ {
47
+ "type": "function",
48
+ "function": {
49
+ "name": "complete_task",
50
+ "description": "Mark a task as completed. IMPORTANT: You must first call list_tasks to get the task UUID, then use that UUID here.",
51
+ "parameters": {
52
+ "type": "object",
53
+ "properties": {
54
+ "user_id": {"type": "string", "description": "The user's unique identifier"},
55
+ "task_id": {"type": "string", "description": "The task's UUID (e.g., 'd18627f4-73ff-4450-943e-451c24962de0'). NOT the task
56
+ title!"}
57
+ },
58
+ "required": ["user_id", "task_id"]
59
+ }
60
+ }
61
+ },
62
+ {
63
+ "type": "function",
64
+ "function": {
65
+ "name": "update_task",
66
+ "description": "Update a task's title or description",
67
+ "parameters": {
68
+ "type": "object",
69
+ "properties": {
70
+ "user_id": {"type": "string", "description": "The user's unique identifier"},
71
+ "task_id": {"type": "string", "description": "The task's unique identifier (UUID)"},
72
+ "title": {"type": "string", "description": "New task title"},
73
+ "description": {"type": "string", "description": "New task description"}
74
+ },
75
+ "required": ["user_id", "task_id"]
76
+ }
77
+ }
78
+ },
79
+ {
80
+ "type": "function",
81
+ "function": {
82
+ "name": "delete_task",
83
+ "description": "Permanently delete a task",
84
+ "parameters": {
85
+ "type": "object",
86
+ "properties": {
87
+ "user_id": {"type": "string", "description": "The user's unique identifier"},
88
+ "task_id": {"type": "string", "description": "The task's unique identifier (UUID)"}
89
+ },
90
+ "required": ["user_id", "task_id"]
91
+ }
92
+ }
93
+ }
94
+ ]
95
+
96
+
97
+ def execute_tool(name: str, arguments: dict) -> Any:
98
+ """Execute a tool by name with given arguments."""
99
+ if name == "add_task":
100
+ return mcp_tools.add_task(
101
+ arguments["user_id"],
102
+ arguments["title"],
103
+ arguments.get("description")
104
+ )
105
+ elif name == "list_tasks":
106
+ return mcp_tools.list_tasks(arguments["user_id"])
107
+ elif name == "complete_task":
108
+ return mcp_tools.complete_task(arguments["user_id"], arguments["task_id"])
109
+ elif name == "update_task":
110
+ return mcp_tools.update_task(
111
+ arguments["user_id"],
112
+ arguments["task_id"],
113
+ arguments.get("title"),
114
+ arguments.get("description")
115
+ )
116
+ elif name == "delete_task":
117
+ return mcp_tools.delete_task(arguments["user_id"], arguments["task_id"])
118
+ else:
119
+ return {"error": f"Unknown tool: {name}"}
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
 
122
+ class TaskAgent:
123
  """
124
  AI agent for task management via natural language.
125
  Uses OpenAI API directly for reliable tool/function calling support.
 
142
  )
143
  # Use gpt-4o-mini for fast, reliable tool calling
144
  self.model = model or "gpt-4o-mini"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
145
 
146
+ async def run(
147
+ self,
148
+ message: str,
149
+ user_id: str,
150
+ context: dict[str, Any] | None = None
151
+ ) -> dict[str, Any]:
152
+ """
153
+ Process a user message and return the agent's response.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
 
155
+ Args:
156
+ message: User's natural language message
157
+ user_id: User identifier for tool calls
158
+ context: Optional additional context
159
 
160
+ Returns:
161
+ dict with response and tool_calls
162
+ """
163
+ # Build messages
164
+ messages = [
165
+ {"role": "system", "content": SYSTEM_PROMPT + f"\n\nCurrent User ID: {user_id}"}
166
+ ]
167
+
168
+ # Add conversation history if available
169
+ if context and context.get("conversation_history"):
170
+ for msg in context["conversation_history"][-5:]:
171
+ messages.append({
172
+ "role": msg["role"],
173
+ "content": msg["content"]
174
+ })
175
+
176
+ # Add current user message
177
+ messages.append({"role": "user", "content": message})
178
+
179
+ tool_calls_made = []
180
+
181
+ # Call the model
182
+ response = await self.client.chat.completions.create(
183
+ model=self.model,
184
+ messages=messages,
185
+ tools=TOOLS,
186
+ tool_choice="auto",
187
+ )
188
 
189
+ assistant_message = response.choices[0].message
190
+
191
+ # Handle tool calls if any
192
+ while assistant_message.tool_calls:
193
+ # Add assistant message with tool calls
194
+ messages.append(assistant_message)
195
+
196
+ # Execute each tool call
197
+ for tool_call in assistant_message.tool_calls:
198
+ function_name = tool_call.function.name
199
+ arguments = json.loads(tool_call.function.arguments)
200
+
201
+ # Inject user_id if not provided
202
+ if "user_id" not in arguments:
203
+ arguments["user_id"] = user_id
204
+
205
+ # Execute the tool
206
+ result = execute_tool(function_name, arguments)
207
+
208
+ tool_calls_made.append({
209
+ "name": function_name,
210
+ "arguments": arguments,
211
+ "result": result
212
+ })
213
+
214
+ # Add tool result to messages
215
+ messages.append({
216
+ "role": "tool",
217
+ "tool_call_id": tool_call.id,
218
+ "content": json.dumps(result)
219
+ })
220
+
221
+ # Get next response
222
+ response = await self.client.chat.completions.create(
223
+ model=self.model,
224
+ messages=messages,
225
+ tools=TOOLS,
226
+ tool_choice="auto",
227
+ )
228
+ assistant_message = response.choices[0].message
229
+
230
+ # Get final text response
231
+ response_text = assistant_message.content or ""
232
+
233
+ return {
234
+ "response": response_text,
235
+ "tool_calls": tool_calls_made
236
+ }
237
+
238
+
239
+ def create_task_agent(model: str | None = None) -> TaskAgent:
240
+ """Factory function to create a TaskAgent instance."""
241
+ return TaskAgent(model=model)