praisonaiagents 0.0.6__py3-none-any.whl → 0.0.8__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- praisonaiagents/agent/agent.py +140 -67
- {praisonaiagents-0.0.6.dist-info → praisonaiagents-0.0.8.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.6.dist-info → praisonaiagents-0.0.8.dist-info}/RECORD +5 -5
- {praisonaiagents-0.0.6.dist-info → praisonaiagents-0.0.8.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.6.dist-info → praisonaiagents-0.0.8.dist-info}/top_level.txt +0 -0
praisonaiagents/agent/agent.py
CHANGED
@@ -17,13 +17,92 @@ from ..main import (
|
|
17
17
|
)
|
18
18
|
|
19
19
|
class Agent:
|
20
|
+
def _generate_tool_definition(self, function_name):
|
21
|
+
"""
|
22
|
+
Generate a tool definition from a function name by inspecting the function.
|
23
|
+
"""
|
24
|
+
# First try to get the tool definition if it exists
|
25
|
+
tool_def_name = f"{function_name}_definition"
|
26
|
+
tool_def = globals().get(tool_def_name)
|
27
|
+
if not tool_def:
|
28
|
+
import __main__
|
29
|
+
tool_def = getattr(__main__, tool_def_name, None)
|
30
|
+
|
31
|
+
if tool_def:
|
32
|
+
return tool_def
|
33
|
+
|
34
|
+
# If no definition exists, try to generate one from the function
|
35
|
+
func = globals().get(function_name)
|
36
|
+
if not func:
|
37
|
+
import __main__
|
38
|
+
func = getattr(__main__, function_name, None)
|
39
|
+
|
40
|
+
if not func or not callable(func):
|
41
|
+
return None
|
42
|
+
|
43
|
+
import inspect
|
44
|
+
sig = inspect.signature(func)
|
45
|
+
parameters = {
|
46
|
+
"type": "object",
|
47
|
+
"properties": {},
|
48
|
+
"required": []
|
49
|
+
}
|
50
|
+
|
51
|
+
# Parse docstring for parameter descriptions
|
52
|
+
docstring = inspect.getdoc(func)
|
53
|
+
param_descriptions = {}
|
54
|
+
if docstring:
|
55
|
+
import re
|
56
|
+
param_section = re.split(r'\s*Args:\s*', docstring)
|
57
|
+
if len(param_section) > 1:
|
58
|
+
param_lines = param_section[1].split('\n')
|
59
|
+
for line in param_lines:
|
60
|
+
line = line.strip()
|
61
|
+
if line and ':' in line:
|
62
|
+
param_name, param_desc = line.split(':', 1)
|
63
|
+
param_descriptions[param_name.strip()] = param_desc.strip()
|
64
|
+
|
65
|
+
for name, param in sig.parameters.items():
|
66
|
+
param_type = "string" # Default type
|
67
|
+
if param.annotation != inspect.Parameter.empty:
|
68
|
+
if param.annotation == int:
|
69
|
+
param_type = "integer"
|
70
|
+
elif param.annotation == float:
|
71
|
+
param_type = "number"
|
72
|
+
elif param.annotation == bool:
|
73
|
+
param_type = "boolean"
|
74
|
+
elif param.annotation == list:
|
75
|
+
param_type = "array"
|
76
|
+
elif param.annotation == dict:
|
77
|
+
param_type = "object"
|
78
|
+
|
79
|
+
param_info = {"type": param_type}
|
80
|
+
if name in param_descriptions:
|
81
|
+
param_info["description"] = param_descriptions[name]
|
82
|
+
|
83
|
+
parameters["properties"][name] = param_info
|
84
|
+
if param.default == inspect.Parameter.empty:
|
85
|
+
parameters["required"].append(name)
|
86
|
+
|
87
|
+
# Extract description from docstring
|
88
|
+
description = docstring.split('\n')[0] if docstring else f"Function {function_name}"
|
89
|
+
|
90
|
+
return {
|
91
|
+
"type": "function",
|
92
|
+
"function": {
|
93
|
+
"name": function_name,
|
94
|
+
"description": description,
|
95
|
+
"parameters": parameters
|
96
|
+
}
|
97
|
+
}
|
98
|
+
|
20
99
|
def __init__(
|
21
100
|
self,
|
22
101
|
name: str,
|
23
102
|
role: str,
|
24
103
|
goal: str,
|
25
104
|
backstory: str,
|
26
|
-
llm: Optional[Union[str, Any]] = "gpt-4o
|
105
|
+
llm: Optional[Union[str, Any]] = "gpt-4o",
|
27
106
|
tools: Optional[List[Any]] = None,
|
28
107
|
function_calling_llm: Optional[Any] = None,
|
29
108
|
max_iter: int = 20,
|
@@ -46,14 +125,16 @@ class Agent:
|
|
46
125
|
use_system_prompt: Optional[bool] = True,
|
47
126
|
markdown: bool = True,
|
48
127
|
self_reflect: bool = True,
|
49
|
-
|
128
|
+
max_reflect: int = 3,
|
129
|
+
min_reflect: int = 1,
|
130
|
+
reflect_llm: Optional[str] = None
|
50
131
|
):
|
51
132
|
self.name = name
|
52
133
|
self.role = role
|
53
134
|
self.goal = goal
|
54
135
|
self.backstory = backstory
|
55
136
|
self.llm = llm
|
56
|
-
self.tools = tools if tools else []
|
137
|
+
self.tools = tools if tools else [] # Store original tools
|
57
138
|
self.function_calling_llm = function_calling_llm
|
58
139
|
self.max_iter = max_iter
|
59
140
|
self.max_rpm = max_rpm
|
@@ -76,21 +157,29 @@ class Agent:
|
|
76
157
|
self.chat_history = []
|
77
158
|
self.markdown = markdown
|
78
159
|
self.self_reflect = self_reflect
|
79
|
-
self.
|
80
|
-
|
160
|
+
self.max_reflect = max_reflect
|
161
|
+
self.min_reflect = min_reflect
|
162
|
+
self.reflect_llm = reflect_llm
|
81
163
|
def execute_tool(self, function_name, arguments):
|
164
|
+
"""
|
165
|
+
Execute a tool dynamically based on the function name and arguments.
|
166
|
+
"""
|
82
167
|
logging.debug(f"{self.name} executing tool {function_name} with arguments: {arguments}")
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
168
|
+
|
169
|
+
# Try to get the function from globals first
|
170
|
+
func = globals().get(function_name)
|
171
|
+
if not func:
|
172
|
+
# Then try to get from the main module
|
173
|
+
import __main__
|
174
|
+
func = getattr(__main__, function_name, None)
|
175
|
+
|
176
|
+
if func and callable(func):
|
177
|
+
try:
|
178
|
+
return func(**arguments)
|
179
|
+
except Exception as e:
|
180
|
+
return {"error": str(e)}
|
181
|
+
|
182
|
+
return {"error": f"Tool '{function_name}' is not callable"}
|
94
183
|
|
95
184
|
def clear_history(self):
|
96
185
|
self.chat_history = []
|
@@ -104,26 +193,25 @@ class Agent:
|
|
104
193
|
logging.debug(f"{self.name} sending messages to LLM: {messages}")
|
105
194
|
|
106
195
|
formatted_tools = []
|
196
|
+
if tools is None:
|
197
|
+
tools = self.tools
|
107
198
|
if tools:
|
108
199
|
for tool in tools:
|
109
|
-
if isinstance(tool,
|
200
|
+
if isinstance(tool, str):
|
201
|
+
# Generate tool definition for string tool names
|
202
|
+
tool_def = self._generate_tool_definition(tool)
|
203
|
+
if tool_def:
|
204
|
+
formatted_tools.append(tool_def)
|
205
|
+
else:
|
206
|
+
logging.warning(f"Could not generate definition for tool: {tool}")
|
207
|
+
elif isinstance(tool, dict):
|
110
208
|
formatted_tools.append(tool)
|
111
209
|
elif hasattr(tool, "to_openai_tool"):
|
112
210
|
formatted_tools.append(tool.to_openai_tool())
|
113
|
-
elif
|
114
|
-
formatted_tools.append(
|
115
|
-
"type": "function",
|
116
|
-
"function": {
|
117
|
-
"name": tool,
|
118
|
-
"description": f"This is a tool called {tool}",
|
119
|
-
"parameters": {
|
120
|
-
"type": "object",
|
121
|
-
"properties": {},
|
122
|
-
},
|
123
|
-
}
|
124
|
-
})
|
211
|
+
elif callable(tool):
|
212
|
+
formatted_tools.append(self._generate_tool_definition(tool.__name__))
|
125
213
|
else:
|
126
|
-
|
214
|
+
logging.warning(f"Tool {tool} not recognized")
|
127
215
|
|
128
216
|
try:
|
129
217
|
initial_response = client.chat.completions.create(
|
@@ -223,29 +311,7 @@ class Agent:
|
|
223
311
|
if self.verbose:
|
224
312
|
display_instruction(f"Agent {self.name} is processing prompt: {prompt}")
|
225
313
|
|
226
|
-
|
227
|
-
if tools:
|
228
|
-
for tool in tools:
|
229
|
-
if isinstance(tool, dict):
|
230
|
-
formatted_tools.append(tool)
|
231
|
-
elif hasattr(tool, "to_openai_tool"):
|
232
|
-
formatted_tools.append(tool.to_openai_tool())
|
233
|
-
elif isinstance(tool, str):
|
234
|
-
formatted_tools.append({
|
235
|
-
"type": "function",
|
236
|
-
"function": {
|
237
|
-
"name": tool,
|
238
|
-
"description": f"This is a tool called {tool}",
|
239
|
-
"parameters": {
|
240
|
-
"type": "object",
|
241
|
-
"properties": {},
|
242
|
-
},
|
243
|
-
}
|
244
|
-
})
|
245
|
-
else:
|
246
|
-
display_error(f"Warning: Tool {tool} not recognized")
|
247
|
-
|
248
|
-
response = self._chat_completion(messages, temperature=temperature, tools=formatted_tools if formatted_tools else None)
|
314
|
+
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None)
|
249
315
|
if not response:
|
250
316
|
return None
|
251
317
|
|
@@ -308,7 +374,7 @@ class Agent:
|
|
308
374
|
|
309
375
|
try:
|
310
376
|
reflection_response = client.beta.chat.completions.parse(
|
311
|
-
model=self.llm,
|
377
|
+
model=self.reflect_llm if self.reflect_llm else self.llm,
|
312
378
|
messages=messages,
|
313
379
|
temperature=temperature,
|
314
380
|
response_format=ReflectionOutput
|
@@ -317,35 +383,42 @@ class Agent:
|
|
317
383
|
reflection_output = reflection_response.choices[0].message.parsed
|
318
384
|
|
319
385
|
if self.verbose:
|
320
|
-
display_self_reflection(f"Agent {self.name} self reflection: reflection='{reflection_output.reflection}' satisfactory='{reflection_output.satisfactory}'")
|
386
|
+
display_self_reflection(f"Agent {self.name} self reflection (using {self.reflect_llm if self.reflect_llm else self.llm}): reflection='{reflection_output.reflection}' satisfactory='{reflection_output.satisfactory}'")
|
321
387
|
|
322
388
|
messages.append({"role": "assistant", "content": f"Self Reflection: {reflection_output.reflection} Satisfactory?: {reflection_output.satisfactory}"})
|
323
389
|
|
324
|
-
|
390
|
+
# Only consider satisfactory after minimum reflections
|
391
|
+
if reflection_output.satisfactory == "yes" and reflection_count >= self.min_reflect - 1:
|
392
|
+
if self.verbose:
|
393
|
+
display_self_reflection("Agent marked the response as satisfactory after meeting minimum reflections")
|
394
|
+
self.chat_history.append({"role": "user", "content": prompt})
|
395
|
+
self.chat_history.append({"role": "assistant", "content": response_text})
|
396
|
+
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
|
397
|
+
return response_text
|
398
|
+
|
399
|
+
# Check if we've hit max reflections
|
400
|
+
if reflection_count >= self.max_reflect - 1:
|
325
401
|
if self.verbose:
|
326
|
-
display_self_reflection("
|
402
|
+
display_self_reflection("Maximum reflection count reached, returning current response")
|
403
|
+
self.chat_history.append({"role": "user", "content": prompt})
|
327
404
|
self.chat_history.append({"role": "assistant", "content": response_text})
|
328
405
|
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
|
329
406
|
return response_text
|
330
407
|
|
331
|
-
logging.debug(f"{self.name} reflection
|
408
|
+
logging.debug(f"{self.name} reflection count {reflection_count + 1}, continuing reflection process")
|
332
409
|
messages.append({"role": "user", "content": "Now regenerate your response using the reflection you made"})
|
333
410
|
response = self._chat_completion(messages, temperature=temperature, tools=None, stream=True)
|
334
411
|
response_text = response.choices[0].message.content.strip()
|
412
|
+
reflection_count += 1
|
413
|
+
continue # Continue the loop for more reflections
|
414
|
+
|
335
415
|
except Exception as e:
|
336
416
|
display_error(f"Error in parsing self-reflection json {e}. Retrying")
|
337
417
|
logging.error("Reflection parsing failed.", exc_info=True)
|
338
418
|
messages.append({"role": "assistant", "content": f"Self Reflection failed."})
|
419
|
+
reflection_count += 1
|
420
|
+
continue # Continue even after error to try again
|
339
421
|
|
340
|
-
reflection_count += 1
|
341
|
-
|
342
|
-
self.chat_history.append({"role": "user", "content": prompt})
|
343
|
-
self.chat_history.append({"role": "assistant", "content": response_text})
|
344
|
-
|
345
|
-
if self.verbose:
|
346
|
-
logging.info(f"Agent {self.name} final response: {response_text}")
|
347
|
-
display_interaction(prompt, response_text, markdown=self.markdown, generation_time=time.time() - start_time)
|
348
|
-
return response_text
|
349
422
|
except Exception as e:
|
350
423
|
display_error(f"Error in chat: {e}")
|
351
424
|
return None
|
@@ -1,7 +1,7 @@
|
|
1
1
|
praisonaiagents/__init__.py,sha256=gI8vEabBTRPsE_E8GA5sBMi4sTtJI-YokPrH2Nor-k0,741
|
2
2
|
praisonaiagents/main.py,sha256=zDhN5KKtKbfruolDNxlyJkcFlkSt4KQkQTDRfQVAhxc,3960
|
3
3
|
praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
|
4
|
-
praisonaiagents/agent/agent.py,sha256=
|
4
|
+
praisonaiagents/agent/agent.py,sha256=ov7WrSpgsbjqLt2yJVEmqVyVMPJqBgwkUTk1tim0dGg,18241
|
5
5
|
praisonaiagents/agents/__init__.py,sha256=7RDeQNSqZg5uBjD4M_0p_F6YgfWuDuxPFydPU50kDYc,120
|
6
6
|
praisonaiagents/agents/agents.py,sha256=NkosnTo41bB9H0lYt_YQIHwaRyW2Bcp_4KKpYWeaFk0,13696
|
7
7
|
praisonaiagents/build/lib/praisonaiagents/__init__.py,sha256=Nqnn8clbgv-5l0PgxcTOldg8mkMKrFn4TvPL-rYUUGg,1
|
@@ -14,7 +14,7 @@ praisonaiagents/build/lib/praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb3
|
|
14
14
|
praisonaiagents/build/lib/praisonaiagents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
|
15
15
|
praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
|
16
16
|
praisonaiagents/task/task.py,sha256=4Y1qX8OeEFcid2yhAiPYylvHpuDmWORsyNL16_BiVvI,1831
|
17
|
-
praisonaiagents-0.0.
|
18
|
-
praisonaiagents-0.0.
|
19
|
-
praisonaiagents-0.0.
|
20
|
-
praisonaiagents-0.0.
|
17
|
+
praisonaiagents-0.0.8.dist-info/METADATA,sha256=wIiXOiCtBxNdqhBruAc7ECloBsy_SIW-K33C1acNfOI,232
|
18
|
+
praisonaiagents-0.0.8.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
19
|
+
praisonaiagents-0.0.8.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
20
|
+
praisonaiagents-0.0.8.dist-info/RECORD,,
|
File without changes
|
File without changes
|