praisonaiagents 0.0.50__py3-none-any.whl → 0.0.52__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 +186 -18
- praisonaiagents/llm/llm.py +318 -124
- {praisonaiagents-0.0.50.dist-info → praisonaiagents-0.0.52.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.50.dist-info → praisonaiagents-0.0.52.dist-info}/RECORD +6 -6
- {praisonaiagents-0.0.50.dist-info → praisonaiagents-0.0.52.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.50.dist-info → praisonaiagents-0.0.52.dist-info}/top_level.txt +0 -0
praisonaiagents/agent/agent.py
CHANGED
@@ -21,10 +21,137 @@ from ..main import (
|
|
21
21
|
)
|
22
22
|
import inspect
|
23
23
|
import uuid
|
24
|
+
from dataclasses import dataclass
|
24
25
|
|
25
26
|
if TYPE_CHECKING:
|
26
27
|
from ..task.task import Task
|
27
28
|
|
29
|
+
@dataclass
|
30
|
+
class ChatCompletionMessage:
|
31
|
+
content: str
|
32
|
+
role: str = "assistant"
|
33
|
+
refusal: Optional[str] = None
|
34
|
+
audio: Optional[str] = None
|
35
|
+
function_call: Optional[dict] = None
|
36
|
+
tool_calls: Optional[List] = None
|
37
|
+
reasoning_content: Optional[str] = None
|
38
|
+
|
39
|
+
@dataclass
|
40
|
+
class Choice:
|
41
|
+
finish_reason: Optional[str]
|
42
|
+
index: int
|
43
|
+
message: ChatCompletionMessage
|
44
|
+
logprobs: Optional[dict] = None
|
45
|
+
|
46
|
+
@dataclass
|
47
|
+
class CompletionTokensDetails:
|
48
|
+
accepted_prediction_tokens: Optional[int] = None
|
49
|
+
audio_tokens: Optional[int] = None
|
50
|
+
reasoning_tokens: Optional[int] = None
|
51
|
+
rejected_prediction_tokens: Optional[int] = None
|
52
|
+
|
53
|
+
@dataclass
|
54
|
+
class PromptTokensDetails:
|
55
|
+
audio_tokens: Optional[int] = None
|
56
|
+
cached_tokens: int = 0
|
57
|
+
|
58
|
+
@dataclass
|
59
|
+
class CompletionUsage:
|
60
|
+
completion_tokens: int = 0
|
61
|
+
prompt_tokens: int = 0
|
62
|
+
total_tokens: int = 0
|
63
|
+
completion_tokens_details: Optional[CompletionTokensDetails] = None
|
64
|
+
prompt_tokens_details: Optional[PromptTokensDetails] = None
|
65
|
+
prompt_cache_hit_tokens: int = 0
|
66
|
+
prompt_cache_miss_tokens: int = 0
|
67
|
+
|
68
|
+
@dataclass
|
69
|
+
class ChatCompletion:
|
70
|
+
id: str
|
71
|
+
choices: List[Choice]
|
72
|
+
created: int
|
73
|
+
model: str
|
74
|
+
object: str = "chat.completion"
|
75
|
+
system_fingerprint: Optional[str] = None
|
76
|
+
service_tier: Optional[str] = None
|
77
|
+
usage: Optional[CompletionUsage] = None
|
78
|
+
|
79
|
+
def process_stream_chunks(chunks):
|
80
|
+
"""Process streaming chunks into combined response"""
|
81
|
+
if not chunks:
|
82
|
+
return None
|
83
|
+
|
84
|
+
try:
|
85
|
+
first_chunk = chunks[0]
|
86
|
+
last_chunk = chunks[-1]
|
87
|
+
|
88
|
+
# Basic metadata
|
89
|
+
id = getattr(first_chunk, "id", None)
|
90
|
+
created = getattr(first_chunk, "created", None)
|
91
|
+
model = getattr(first_chunk, "model", None)
|
92
|
+
system_fingerprint = getattr(first_chunk, "system_fingerprint", None)
|
93
|
+
|
94
|
+
# Track usage
|
95
|
+
completion_tokens = 0
|
96
|
+
prompt_tokens = 0
|
97
|
+
|
98
|
+
content_list = []
|
99
|
+
reasoning_list = []
|
100
|
+
|
101
|
+
for chunk in chunks:
|
102
|
+
if not hasattr(chunk, "choices") or not chunk.choices:
|
103
|
+
continue
|
104
|
+
|
105
|
+
# Track usage from each chunk
|
106
|
+
if hasattr(chunk, "usage"):
|
107
|
+
completion_tokens += getattr(chunk.usage, "completion_tokens", 0)
|
108
|
+
prompt_tokens += getattr(chunk.usage, "prompt_tokens", 0)
|
109
|
+
|
110
|
+
delta = getattr(chunk.choices[0], "delta", None)
|
111
|
+
if not delta:
|
112
|
+
continue
|
113
|
+
|
114
|
+
if hasattr(delta, "content") and delta.content:
|
115
|
+
content_list.append(delta.content)
|
116
|
+
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
|
117
|
+
reasoning_list.append(delta.reasoning_content)
|
118
|
+
|
119
|
+
combined_content = "".join(content_list) if content_list else ""
|
120
|
+
combined_reasoning = "".join(reasoning_list) if reasoning_list else None
|
121
|
+
finish_reason = getattr(last_chunk.choices[0], "finish_reason", None) if hasattr(last_chunk, "choices") and last_chunk.choices else None
|
122
|
+
|
123
|
+
message = ChatCompletionMessage(
|
124
|
+
content=combined_content,
|
125
|
+
reasoning_content=combined_reasoning
|
126
|
+
)
|
127
|
+
|
128
|
+
choice = Choice(
|
129
|
+
finish_reason=finish_reason,
|
130
|
+
index=0,
|
131
|
+
message=message
|
132
|
+
)
|
133
|
+
|
134
|
+
usage = CompletionUsage(
|
135
|
+
completion_tokens=completion_tokens,
|
136
|
+
prompt_tokens=prompt_tokens,
|
137
|
+
total_tokens=completion_tokens + prompt_tokens,
|
138
|
+
completion_tokens_details=CompletionTokensDetails(),
|
139
|
+
prompt_tokens_details=PromptTokensDetails()
|
140
|
+
)
|
141
|
+
|
142
|
+
return ChatCompletion(
|
143
|
+
id=id,
|
144
|
+
choices=[choice],
|
145
|
+
created=created,
|
146
|
+
model=model,
|
147
|
+
system_fingerprint=system_fingerprint,
|
148
|
+
usage=usage
|
149
|
+
)
|
150
|
+
|
151
|
+
except Exception as e:
|
152
|
+
print(f"Error processing chunks: {e}")
|
153
|
+
return None
|
154
|
+
|
28
155
|
class Agent:
|
29
156
|
def _generate_tool_definition(self, function_name):
|
30
157
|
"""
|
@@ -190,7 +317,8 @@ class Agent:
|
|
190
317
|
max_reflect: int = 3,
|
191
318
|
min_reflect: int = 1,
|
192
319
|
reflect_llm: Optional[str] = None,
|
193
|
-
user_id: Optional[str] = None
|
320
|
+
user_id: Optional[str] = None,
|
321
|
+
show_reasoning: bool = False
|
194
322
|
):
|
195
323
|
# Add check at start if memory is requested
|
196
324
|
if memory is not None:
|
@@ -298,6 +426,7 @@ Your Goal: {self.goal}
|
|
298
426
|
|
299
427
|
# Store user_id
|
300
428
|
self.user_id = user_id or "praison"
|
429
|
+
self.show_reasoning = show_reasoning
|
301
430
|
|
302
431
|
# Check if knowledge parameter has any values
|
303
432
|
if not knowledge:
|
@@ -399,7 +528,7 @@ Your Goal: {self.goal}
|
|
399
528
|
def __str__(self):
|
400
529
|
return f"Agent(name='{self.name}', role='{self.role}', goal='{self.goal}')"
|
401
530
|
|
402
|
-
def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True):
|
531
|
+
def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True, show_reasoning=False):
|
403
532
|
start_time = time.time()
|
404
533
|
logging.debug(f"{self.name} sending messages to LLM: {messages}")
|
405
534
|
|
@@ -469,30 +598,35 @@ Your Goal: {self.goal}
|
|
469
598
|
stream=True
|
470
599
|
)
|
471
600
|
full_response_text = ""
|
601
|
+
reasoning_content = ""
|
602
|
+
chunks = []
|
472
603
|
|
473
604
|
# Create Live display with proper configuration
|
474
605
|
with Live(
|
475
606
|
display_generating("", start_time),
|
476
607
|
console=self.console,
|
477
608
|
refresh_per_second=4,
|
478
|
-
transient=True,
|
609
|
+
transient=True,
|
479
610
|
vertical_overflow="ellipsis",
|
480
611
|
auto_refresh=True
|
481
612
|
) as live:
|
482
613
|
for chunk in response_stream:
|
614
|
+
chunks.append(chunk)
|
483
615
|
if chunk.choices[0].delta.content:
|
484
616
|
full_response_text += chunk.choices[0].delta.content
|
485
617
|
live.update(display_generating(full_response_text, start_time))
|
618
|
+
|
619
|
+
# Update live display with reasoning content if enabled
|
620
|
+
if show_reasoning and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
621
|
+
rc = chunk.choices[0].delta.reasoning_content
|
622
|
+
if rc:
|
623
|
+
reasoning_content += rc
|
624
|
+
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
486
625
|
|
487
626
|
# Clear the last generating display with a blank line
|
488
627
|
self.console.print()
|
489
628
|
|
490
|
-
final_response =
|
491
|
-
model=self.llm,
|
492
|
-
messages=messages,
|
493
|
-
temperature=temperature,
|
494
|
-
stream=False
|
495
|
-
)
|
629
|
+
final_response = process_stream_chunks(chunks)
|
496
630
|
return final_response
|
497
631
|
else:
|
498
632
|
if tool_calls:
|
@@ -510,7 +644,8 @@ Your Goal: {self.goal}
|
|
510
644
|
display_error(f"Error in chat completion: {e}")
|
511
645
|
return None
|
512
646
|
|
513
|
-
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
647
|
+
def chat(self, prompt, temperature=0.2, tools=None, output_json=None, output_pydantic=None, show_reasoning=False):
|
648
|
+
show_reasoning = show_reasoning or self.show_reasoning
|
514
649
|
# Search for existing knowledge if any knowledge is provided
|
515
650
|
if self.knowledge:
|
516
651
|
search_results = self.knowledge.search(prompt, agent_id=self.agent_id)
|
@@ -546,7 +681,8 @@ Your Goal: {self.goal}
|
|
546
681
|
agent_name=self.name,
|
547
682
|
agent_role=self.role,
|
548
683
|
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools],
|
549
|
-
execute_tool_fn=self.execute_tool # Pass tool execution function
|
684
|
+
execute_tool_fn=self.execute_tool, # Pass tool execution function
|
685
|
+
show_reasoning=show_reasoning
|
550
686
|
)
|
551
687
|
|
552
688
|
self.chat_history.append({"role": "user", "content": prompt})
|
@@ -616,7 +752,7 @@ Your Goal: {self.goal}
|
|
616
752
|
agent_tools=agent_tools
|
617
753
|
)
|
618
754
|
|
619
|
-
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None)
|
755
|
+
response = self._chat_completion(messages, temperature=temperature, tools=tools if tools else None, show_reasoning=show_reasoning)
|
620
756
|
if not response:
|
621
757
|
return None
|
622
758
|
|
@@ -749,8 +885,9 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
749
885
|
cleaned = cleaned[:-3].strip()
|
750
886
|
return cleaned
|
751
887
|
|
752
|
-
async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None):
|
888
|
+
async def achat(self, prompt: str, temperature=0.2, tools=None, output_json=None, output_pydantic=None, show_reasoning=False):
|
753
889
|
"""Async version of chat method. TODO: Requires Syncing with chat method."""
|
890
|
+
show_reasoning = show_reasoning or self.show_reasoning
|
754
891
|
try:
|
755
892
|
# Search for existing knowledge if any knowledge is provided
|
756
893
|
if self.knowledge:
|
@@ -781,7 +918,8 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
781
918
|
agent_name=self.name,
|
782
919
|
agent_role=self.role,
|
783
920
|
agent_tools=[t.__name__ if hasattr(t, '__name__') else str(t) for t in self.tools],
|
784
|
-
execute_tool_fn=self.execute_tool_async
|
921
|
+
execute_tool_fn=self.execute_tool_async,
|
922
|
+
show_reasoning=show_reasoning
|
785
923
|
)
|
786
924
|
|
787
925
|
self.chat_history.append({"role": "user", "content": prompt})
|
@@ -896,7 +1034,7 @@ Your Goal: {self.goal}
|
|
896
1034
|
display_error(f"Error in achat: {e}")
|
897
1035
|
return None
|
898
1036
|
|
899
|
-
async def _achat_completion(self, response, tools):
|
1037
|
+
async def _achat_completion(self, response, tools, show_reasoning=False):
|
900
1038
|
"""Async version of _chat_completion method"""
|
901
1039
|
try:
|
902
1040
|
message = response.choices[0].message
|
@@ -942,9 +1080,39 @@ Your Goal: {self.goal}
|
|
942
1080
|
final_response = await async_client.chat.completions.create(
|
943
1081
|
model=self.llm,
|
944
1082
|
messages=messages,
|
945
|
-
temperature=0.2
|
1083
|
+
temperature=0.2,
|
1084
|
+
stream=True
|
946
1085
|
)
|
947
|
-
|
1086
|
+
full_response_text = ""
|
1087
|
+
reasoning_content = ""
|
1088
|
+
chunks = []
|
1089
|
+
start_time = time.time()
|
1090
|
+
|
1091
|
+
with Live(
|
1092
|
+
display_generating("", start_time),
|
1093
|
+
console=self.console,
|
1094
|
+
refresh_per_second=4,
|
1095
|
+
transient=True,
|
1096
|
+
vertical_overflow="ellipsis",
|
1097
|
+
auto_refresh=True
|
1098
|
+
) as live:
|
1099
|
+
async for chunk in final_response:
|
1100
|
+
chunks.append(chunk)
|
1101
|
+
if chunk.choices[0].delta.content:
|
1102
|
+
full_response_text += chunk.choices[0].delta.content
|
1103
|
+
live.update(display_generating(full_response_text, start_time))
|
1104
|
+
|
1105
|
+
if show_reasoning and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
1106
|
+
rc = chunk.choices[0].delta.reasoning_content
|
1107
|
+
if rc:
|
1108
|
+
reasoning_content += rc
|
1109
|
+
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
1110
|
+
|
1111
|
+
self.console.print()
|
1112
|
+
|
1113
|
+
final_response = process_stream_chunks(chunks)
|
1114
|
+
return final_response.choices[0].message.content if final_response else full_response_text
|
1115
|
+
|
948
1116
|
except Exception as e:
|
949
1117
|
display_error(f"Error in final chat completion: {e}")
|
950
1118
|
return formatted_results
|
@@ -952,7 +1120,7 @@ Your Goal: {self.goal}
|
|
952
1120
|
return None
|
953
1121
|
except Exception as e:
|
954
1122
|
display_error(f"Error in _achat_completion: {e}")
|
955
|
-
return None
|
1123
|
+
return None
|
956
1124
|
|
957
1125
|
async def astart(self, prompt: str, **kwargs):
|
958
1126
|
"""Async version of start method"""
|
praisonaiagents/llm/llm.py
CHANGED
@@ -113,6 +113,7 @@ class LLM:
|
|
113
113
|
litellm.callbacks = []
|
114
114
|
# Additional logging suppression
|
115
115
|
litellm.suppress_debug_messages = True
|
116
|
+
litellm._logging._disable_debugging()
|
116
117
|
logging.getLogger("litellm.utils").setLevel(logging.WARNING)
|
117
118
|
logging.getLogger("litellm.main").setLevel(logging.WARNING)
|
118
119
|
except ImportError:
|
@@ -147,6 +148,7 @@ class LLM:
|
|
147
148
|
self.self_reflect = extra_settings.get('self_reflect', False)
|
148
149
|
self.max_reflect = extra_settings.get('max_reflect', 3)
|
149
150
|
self.min_reflect = extra_settings.get('min_reflect', 1)
|
151
|
+
self.show_reasoning = extra_settings.get('show_reasoning', False)
|
150
152
|
|
151
153
|
# Enable error dropping for cleaner output
|
152
154
|
litellm.drop_params = True
|
@@ -176,7 +178,7 @@ class LLM:
|
|
176
178
|
"""Enhanced get_response with all OpenAI-like features"""
|
177
179
|
try:
|
178
180
|
import litellm
|
179
|
-
|
181
|
+
show_reasoning = kwargs.get('show_reasoning', self.show_reasoning)
|
180
182
|
# Disable litellm debug messages
|
181
183
|
litellm.set_verbose = False
|
182
184
|
|
@@ -230,8 +232,55 @@ class LLM:
|
|
230
232
|
|
231
233
|
# Get response from LiteLLM
|
232
234
|
start_time = time.time()
|
233
|
-
|
234
|
-
|
235
|
+
|
236
|
+
# If show_reasoning is True, do a single non-streaming call
|
237
|
+
if show_reasoning:
|
238
|
+
resp = litellm.completion(
|
239
|
+
model=self.model,
|
240
|
+
messages=messages,
|
241
|
+
temperature=temperature,
|
242
|
+
stream=False, # force non-streaming
|
243
|
+
**kwargs
|
244
|
+
)
|
245
|
+
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
246
|
+
response_text = resp["choices"][0]["message"]["content"]
|
247
|
+
|
248
|
+
# Optionally display reasoning if present
|
249
|
+
if verbose and reasoning_content:
|
250
|
+
display_interaction(
|
251
|
+
original_prompt,
|
252
|
+
f"Reasoning:\n{reasoning_content}\n\nAnswer:\n{response_text}",
|
253
|
+
markdown=markdown,
|
254
|
+
generation_time=time.time() - start_time,
|
255
|
+
console=console
|
256
|
+
)
|
257
|
+
else:
|
258
|
+
display_interaction(
|
259
|
+
original_prompt,
|
260
|
+
response_text,
|
261
|
+
markdown=markdown,
|
262
|
+
generation_time=time.time() - start_time,
|
263
|
+
console=console
|
264
|
+
)
|
265
|
+
|
266
|
+
# Otherwise do the existing streaming approach
|
267
|
+
else:
|
268
|
+
if verbose:
|
269
|
+
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
270
|
+
response_text = ""
|
271
|
+
for chunk in litellm.completion(
|
272
|
+
model=self.model,
|
273
|
+
messages=messages,
|
274
|
+
temperature=temperature,
|
275
|
+
stream=True,
|
276
|
+
**kwargs
|
277
|
+
):
|
278
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
279
|
+
content = chunk.choices[0].delta.content
|
280
|
+
response_text += content
|
281
|
+
live.update(display_generating(response_text, start_time))
|
282
|
+
else:
|
283
|
+
# Non-verbose mode, just collect the response
|
235
284
|
response_text = ""
|
236
285
|
for chunk in litellm.completion(
|
237
286
|
model=self.model,
|
@@ -241,23 +290,9 @@ class LLM:
|
|
241
290
|
**kwargs
|
242
291
|
):
|
243
292
|
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
244
|
-
|
245
|
-
response_text += content
|
246
|
-
live.update(display_generating(response_text, start_time))
|
247
|
-
else:
|
248
|
-
# Non-verbose mode, just collect the response
|
249
|
-
response_text = ""
|
250
|
-
for chunk in litellm.completion(
|
251
|
-
model=self.model,
|
252
|
-
messages=messages,
|
253
|
-
temperature=temperature,
|
254
|
-
stream=True,
|
255
|
-
**kwargs
|
256
|
-
):
|
257
|
-
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
258
|
-
response_text += chunk.choices[0].delta.content
|
293
|
+
response_text += chunk.choices[0].delta.content
|
259
294
|
|
260
|
-
|
295
|
+
response_text = response_text.strip()
|
261
296
|
|
262
297
|
# Get final completion to check for tool calls
|
263
298
|
final_response = litellm.completion(
|
@@ -302,9 +337,53 @@ class LLM:
|
|
302
337
|
"content": "Function returned an empty output"
|
303
338
|
})
|
304
339
|
|
305
|
-
#
|
306
|
-
if
|
307
|
-
|
340
|
+
# If show_reasoning is True, do a single non-streaming call
|
341
|
+
if show_reasoning:
|
342
|
+
resp = litellm.completion(
|
343
|
+
model=self.model,
|
344
|
+
messages=messages,
|
345
|
+
temperature=temperature,
|
346
|
+
stream=False, # force non-streaming
|
347
|
+
**kwargs
|
348
|
+
)
|
349
|
+
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
350
|
+
response_text = resp["choices"][0]["message"]["content"]
|
351
|
+
|
352
|
+
# Optionally display reasoning if present
|
353
|
+
if verbose and reasoning_content:
|
354
|
+
display_interaction(
|
355
|
+
original_prompt,
|
356
|
+
f"Reasoning:\n{reasoning_content}\n\nAnswer:\n{response_text}",
|
357
|
+
markdown=markdown,
|
358
|
+
generation_time=time.time() - start_time,
|
359
|
+
console=console
|
360
|
+
)
|
361
|
+
else:
|
362
|
+
display_interaction(
|
363
|
+
original_prompt,
|
364
|
+
response_text,
|
365
|
+
markdown=markdown,
|
366
|
+
generation_time=time.time() - start_time,
|
367
|
+
console=console
|
368
|
+
)
|
369
|
+
|
370
|
+
# Otherwise do the existing streaming approach
|
371
|
+
else:
|
372
|
+
# Get response after tool calls with streaming
|
373
|
+
if verbose:
|
374
|
+
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
375
|
+
response_text = ""
|
376
|
+
for chunk in litellm.completion(
|
377
|
+
model=self.model,
|
378
|
+
messages=messages,
|
379
|
+
temperature=temperature,
|
380
|
+
stream=True
|
381
|
+
):
|
382
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
383
|
+
content = chunk.choices[0].delta.content
|
384
|
+
response_text += content
|
385
|
+
live.update(display_generating(response_text, start_time))
|
386
|
+
else:
|
308
387
|
response_text = ""
|
309
388
|
for chunk in litellm.completion(
|
310
389
|
model=self.model,
|
@@ -313,21 +392,9 @@ class LLM:
|
|
313
392
|
stream=True
|
314
393
|
):
|
315
394
|
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
316
|
-
|
317
|
-
response_text += content
|
318
|
-
live.update(display_generating(response_text, start_time))
|
319
|
-
else:
|
320
|
-
response_text = ""
|
321
|
-
for chunk in litellm.completion(
|
322
|
-
model=self.model,
|
323
|
-
messages=messages,
|
324
|
-
temperature=temperature,
|
325
|
-
stream=True
|
326
|
-
):
|
327
|
-
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
328
|
-
response_text += chunk.choices[0].delta.content
|
395
|
+
response_text += chunk.choices[0].delta.content
|
329
396
|
|
330
|
-
|
397
|
+
response_text = response_text.strip()
|
331
398
|
|
332
399
|
# Handle output formatting
|
333
400
|
if output_json or output_pydantic:
|
@@ -357,32 +424,66 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
357
424
|
{"role": "user", "content": reflection_prompt}
|
358
425
|
]
|
359
426
|
|
360
|
-
#
|
361
|
-
if
|
362
|
-
|
427
|
+
# If show_reasoning is True, do a single non-streaming call to capture reasoning
|
428
|
+
if show_reasoning:
|
429
|
+
reflection_resp = litellm.completion(
|
430
|
+
model=self.model,
|
431
|
+
messages=reflection_messages,
|
432
|
+
temperature=temperature,
|
433
|
+
stream=False, # Force non-streaming
|
434
|
+
response_format={"type": "json_object"},
|
435
|
+
**kwargs
|
436
|
+
)
|
437
|
+
# Grab reflection text and optional reasoning
|
438
|
+
reasoning_content = reflection_resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
439
|
+
reflection_text = reflection_resp["choices"][0]["message"]["content"]
|
440
|
+
|
441
|
+
# Optionally display reasoning if present
|
442
|
+
if verbose and reasoning_content:
|
443
|
+
display_interaction(
|
444
|
+
"Reflection reasoning:",
|
445
|
+
f"{reasoning_content}\n\nReflection result:\n{reflection_text}",
|
446
|
+
markdown=markdown,
|
447
|
+
generation_time=time.time() - start_time,
|
448
|
+
console=console
|
449
|
+
)
|
450
|
+
elif verbose:
|
451
|
+
display_interaction(
|
452
|
+
"Self-reflection (non-streaming):",
|
453
|
+
reflection_text,
|
454
|
+
markdown=markdown,
|
455
|
+
generation_time=time.time() - start_time,
|
456
|
+
console=console
|
457
|
+
)
|
458
|
+
else:
|
459
|
+
# Existing streaming approach
|
460
|
+
if verbose:
|
461
|
+
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
462
|
+
reflection_text = ""
|
463
|
+
for chunk in litellm.completion(
|
464
|
+
model=self.model,
|
465
|
+
messages=reflection_messages,
|
466
|
+
temperature=temperature,
|
467
|
+
stream=True,
|
468
|
+
response_format={"type": "json_object"},
|
469
|
+
**kwargs
|
470
|
+
):
|
471
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
472
|
+
content = chunk.choices[0].delta.content
|
473
|
+
reflection_text += content
|
474
|
+
live.update(display_generating(reflection_text, start_time))
|
475
|
+
else:
|
363
476
|
reflection_text = ""
|
364
477
|
for chunk in litellm.completion(
|
365
478
|
model=self.model,
|
366
479
|
messages=reflection_messages,
|
367
480
|
temperature=temperature,
|
368
481
|
stream=True,
|
369
|
-
response_format={"type": "json_object"}
|
482
|
+
response_format={"type": "json_object"},
|
483
|
+
**kwargs
|
370
484
|
):
|
371
485
|
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
372
|
-
|
373
|
-
reflection_text += content
|
374
|
-
live.update(display_generating(reflection_text, start_time))
|
375
|
-
else:
|
376
|
-
reflection_text = ""
|
377
|
-
for chunk in litellm.completion(
|
378
|
-
model=self.model,
|
379
|
-
messages=reflection_messages,
|
380
|
-
temperature=temperature,
|
381
|
-
stream=True,
|
382
|
-
response_format={"type": "json_object"}
|
383
|
-
):
|
384
|
-
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
385
|
-
reflection_text += chunk.choices[0].delta.content
|
486
|
+
reflection_text += chunk.choices[0].delta.content
|
386
487
|
|
387
488
|
try:
|
388
489
|
reflection_data = json.loads(reflection_text)
|
@@ -453,6 +554,7 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
453
554
|
"""Async version of get_response with identical functionality."""
|
454
555
|
try:
|
455
556
|
import litellm
|
557
|
+
show_reasoning = kwargs.get('show_reasoning', self.show_reasoning)
|
456
558
|
litellm.set_verbose = False
|
457
559
|
|
458
560
|
# Build messages list
|
@@ -490,10 +592,10 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
490
592
|
# Format tools for LiteLLM
|
491
593
|
formatted_tools = None
|
492
594
|
if tools:
|
493
|
-
logging.
|
595
|
+
logging.debug(f"Starting tool formatting for {len(tools)} tools")
|
494
596
|
formatted_tools = []
|
495
597
|
for tool in tools:
|
496
|
-
logging.
|
598
|
+
logging.debug(f"Processing tool: {tool.__name__ if hasattr(tool, '__name__') else str(tool)}")
|
497
599
|
if hasattr(tool, '__name__'):
|
498
600
|
tool_name = tool.__name__
|
499
601
|
tool_doc = tool.__doc__ or "No description available"
|
@@ -539,10 +641,9 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
539
641
|
}
|
540
642
|
}
|
541
643
|
# Ensure tool definition is JSON serializable
|
542
|
-
print(f"Generated tool definition: {tool_def}")
|
543
644
|
try:
|
544
645
|
json.dumps(tool_def) # Test serialization
|
545
|
-
logging.
|
646
|
+
logging.debug(f"Generated tool definition: {tool_def}")
|
546
647
|
formatted_tools.append(tool_def)
|
547
648
|
except TypeError as e:
|
548
649
|
logging.error(f"Tool definition not JSON serializable: {e}")
|
@@ -552,38 +653,67 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
552
653
|
if formatted_tools:
|
553
654
|
try:
|
554
655
|
json.dumps(formatted_tools) # Final serialization check
|
555
|
-
logging.
|
656
|
+
logging.debug(f"Final formatted tools: {json.dumps(formatted_tools, indent=2)}")
|
556
657
|
except TypeError as e:
|
557
658
|
logging.error(f"Final tools list not JSON serializable: {e}")
|
558
659
|
formatted_tools = None
|
559
660
|
|
560
661
|
response_text = ""
|
561
|
-
if
|
562
|
-
#
|
563
|
-
|
564
|
-
# ----------------------------------------------------
|
565
|
-
async for chunk in await litellm.acompletion(
|
662
|
+
if show_reasoning:
|
663
|
+
# Non-streaming call to capture reasoning
|
664
|
+
resp = await litellm.acompletion(
|
566
665
|
model=self.model,
|
567
666
|
messages=messages,
|
568
667
|
temperature=temperature,
|
569
|
-
stream=
|
668
|
+
stream=False, # force non-streaming
|
570
669
|
**kwargs
|
571
|
-
)
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
670
|
+
)
|
671
|
+
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
672
|
+
response_text = resp["choices"][0]["message"]["content"]
|
673
|
+
|
674
|
+
if verbose and reasoning_content:
|
675
|
+
display_interaction(
|
676
|
+
"Initial reasoning:",
|
677
|
+
f"Reasoning:\n{reasoning_content}\n\nAnswer:\n{response_text}",
|
678
|
+
markdown=markdown,
|
679
|
+
generation_time=time.time() - start_time,
|
680
|
+
console=console
|
681
|
+
)
|
682
|
+
elif verbose:
|
683
|
+
display_interaction(
|
684
|
+
"Initial response:",
|
685
|
+
response_text,
|
686
|
+
markdown=markdown,
|
687
|
+
generation_time=time.time() - start_time,
|
688
|
+
console=console
|
689
|
+
)
|
576
690
|
else:
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
691
|
+
if verbose:
|
692
|
+
# ----------------------------------------------------
|
693
|
+
# 1) Make the streaming call WITHOUT tools
|
694
|
+
# ----------------------------------------------------
|
695
|
+
async for chunk in await litellm.acompletion(
|
696
|
+
model=self.model,
|
697
|
+
messages=messages,
|
698
|
+
temperature=temperature,
|
699
|
+
stream=True,
|
700
|
+
**kwargs
|
701
|
+
):
|
702
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
703
|
+
response_text += chunk.choices[0].delta.content
|
704
|
+
print("\033[K", end="\r")
|
705
|
+
print(f"Generating... {time.time() - start_time:.1f}s", end="\r")
|
706
|
+
else:
|
707
|
+
# Non-verbose streaming call, still no tools
|
708
|
+
async for chunk in await litellm.acompletion(
|
709
|
+
model=self.model,
|
710
|
+
messages=messages,
|
711
|
+
temperature=temperature,
|
712
|
+
stream=True,
|
713
|
+
**kwargs
|
714
|
+
):
|
715
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
716
|
+
response_text += chunk.choices[0].delta.content
|
587
717
|
|
588
718
|
response_text = response_text.strip()
|
589
719
|
|
@@ -634,35 +764,66 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
634
764
|
"content": "Function returned an empty output"
|
635
765
|
})
|
636
766
|
|
637
|
-
# Get response after tool calls
|
767
|
+
# Get response after tool calls
|
638
768
|
response_text = ""
|
639
|
-
if
|
640
|
-
|
769
|
+
if show_reasoning:
|
770
|
+
# Non-streaming call to capture reasoning
|
771
|
+
resp = await litellm.acompletion(
|
641
772
|
model=self.model,
|
642
773
|
messages=messages,
|
643
774
|
temperature=temperature,
|
644
|
-
stream=
|
645
|
-
tools=formatted_tools,
|
775
|
+
stream=False, # force non-streaming
|
776
|
+
tools=formatted_tools, # Include tools
|
646
777
|
**kwargs
|
647
|
-
)
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
660
|
-
|
661
|
-
|
662
|
-
|
663
|
-
|
778
|
+
)
|
779
|
+
reasoning_content = resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
780
|
+
response_text = resp["choices"][0]["message"]["content"]
|
781
|
+
|
782
|
+
if verbose and reasoning_content:
|
783
|
+
display_interaction(
|
784
|
+
"Tool response reasoning:",
|
785
|
+
f"Reasoning:\n{reasoning_content}\n\nAnswer:\n{response_text}",
|
786
|
+
markdown=markdown,
|
787
|
+
generation_time=time.time() - start_time,
|
788
|
+
console=console
|
789
|
+
)
|
790
|
+
elif verbose:
|
791
|
+
display_interaction(
|
792
|
+
"Tool response:",
|
793
|
+
response_text,
|
794
|
+
markdown=markdown,
|
795
|
+
generation_time=time.time() - start_time,
|
796
|
+
console=console
|
797
|
+
)
|
798
|
+
else:
|
799
|
+
# Get response after tool calls with streaming
|
800
|
+
if verbose:
|
801
|
+
async for chunk in await litellm.acompletion(
|
802
|
+
model=self.model,
|
803
|
+
messages=messages,
|
804
|
+
temperature=temperature,
|
805
|
+
stream=True,
|
806
|
+
tools=formatted_tools,
|
807
|
+
**kwargs
|
808
|
+
):
|
809
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
810
|
+
content = chunk.choices[0].delta.content
|
811
|
+
response_text += content
|
812
|
+
print("\033[K", end="\r")
|
813
|
+
print(f"Reflecting... {time.time() - start_time:.1f}s", end="\r")
|
814
|
+
else:
|
815
|
+
response_text = ""
|
816
|
+
for chunk in litellm.completion(
|
817
|
+
model=self.model,
|
818
|
+
messages=messages,
|
819
|
+
temperature=temperature,
|
820
|
+
stream=True,
|
821
|
+
**kwargs
|
822
|
+
):
|
823
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
824
|
+
response_text += chunk.choices[0].delta.content
|
664
825
|
|
665
|
-
|
826
|
+
response_text = response_text.strip()
|
666
827
|
|
667
828
|
# Handle output formatting
|
668
829
|
if output_json or output_pydantic:
|
@@ -692,33 +853,66 @@ Output MUST be JSON with 'reflection' and 'satisfactory'.
|
|
692
853
|
{"role": "user", "content": reflection_prompt}
|
693
854
|
]
|
694
855
|
|
695
|
-
#
|
696
|
-
|
697
|
-
|
698
|
-
async for chunk in await litellm.acompletion(
|
856
|
+
# If show_reasoning is True, do a single non-streaming call to capture reasoning
|
857
|
+
if show_reasoning:
|
858
|
+
reflection_resp = litellm.completion(
|
699
859
|
model=self.model,
|
700
860
|
messages=reflection_messages,
|
701
861
|
temperature=temperature,
|
702
|
-
stream=
|
862
|
+
stream=False, # Force non-streaming
|
703
863
|
response_format={"type": "json_object"},
|
704
864
|
**kwargs
|
705
|
-
)
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
|
710
|
-
|
865
|
+
)
|
866
|
+
# Grab reflection text and optional reasoning
|
867
|
+
reasoning_content = reflection_resp["choices"][0]["message"].get("provider_specific_fields", {}).get("reasoning_content")
|
868
|
+
reflection_text = reflection_resp["choices"][0]["message"]["content"]
|
869
|
+
|
870
|
+
# Optionally display reasoning if present
|
871
|
+
if verbose and reasoning_content:
|
872
|
+
display_interaction(
|
873
|
+
"Reflection reasoning:",
|
874
|
+
f"{reasoning_content}\n\nReflection result:\n{reflection_text}",
|
875
|
+
markdown=markdown,
|
876
|
+
generation_time=time.time() - start_time,
|
877
|
+
console=console
|
878
|
+
)
|
879
|
+
elif verbose:
|
880
|
+
display_interaction(
|
881
|
+
"Self-reflection (non-streaming):",
|
882
|
+
reflection_text,
|
883
|
+
markdown=markdown,
|
884
|
+
generation_time=time.time() - start_time,
|
885
|
+
console=console
|
886
|
+
)
|
711
887
|
else:
|
712
|
-
|
713
|
-
|
714
|
-
|
715
|
-
|
716
|
-
|
717
|
-
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
888
|
+
# Existing streaming approach
|
889
|
+
if verbose:
|
890
|
+
with Live(display_generating("", start_time), console=console, refresh_per_second=4) as live:
|
891
|
+
reflection_text = ""
|
892
|
+
for chunk in litellm.completion(
|
893
|
+
model=self.model,
|
894
|
+
messages=reflection_messages,
|
895
|
+
temperature=temperature,
|
896
|
+
stream=True,
|
897
|
+
response_format={"type": "json_object"},
|
898
|
+
**kwargs
|
899
|
+
):
|
900
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
901
|
+
content = chunk.choices[0].delta.content
|
902
|
+
reflection_text += content
|
903
|
+
live.update(display_generating(reflection_text, start_time))
|
904
|
+
else:
|
905
|
+
reflection_text = ""
|
906
|
+
for chunk in litellm.completion(
|
907
|
+
model=self.model,
|
908
|
+
messages=reflection_messages,
|
909
|
+
temperature=temperature,
|
910
|
+
stream=True,
|
911
|
+
response_format={"type": "json_object"},
|
912
|
+
**kwargs
|
913
|
+
):
|
914
|
+
if chunk and chunk.choices and chunk.choices[0].delta.content:
|
915
|
+
reflection_text += chunk.choices[0].delta.content
|
722
916
|
|
723
917
|
while True: # Add loop for reflection handling
|
724
918
|
try:
|
@@ -1,7 +1,7 @@
|
|
1
1
|
praisonaiagents/__init__.py,sha256=JtPibbmeFv3meIb3vkKjckB0p7m-Vqt2RYPwOH8P41k,1228
|
2
2
|
praisonaiagents/main.py,sha256=0kB9gn9meXtr4EIrdgA2lAioKIHCRJ61audsGDwuTm4,14428
|
3
3
|
praisonaiagents/agent/__init__.py,sha256=sKO8wGEXvtCrvV1e834r1Okv0XAqAxqZCqz6hKLiTvA,79
|
4
|
-
praisonaiagents/agent/agent.py,sha256=
|
4
|
+
praisonaiagents/agent/agent.py,sha256=9r9eN9sTI3A_3IZdA4GYpsKXE5Q4m8yQ_QXGyFirQok,53844
|
5
5
|
praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
|
6
6
|
praisonaiagents/agents/agents.py,sha256=PRqBEUqRadVLBoDd-tgne5fVB87bR6P9qOgvDdjS-dY,37028
|
7
7
|
praisonaiagents/agents/autoagents.py,sha256=bjC2O5oZmoJItJXIMPTWc2lsp_AJC9tMiTQOal2hwPA,13532
|
@@ -9,7 +9,7 @@ praisonaiagents/knowledge/__init__.py,sha256=xL1Eh-a3xsHyIcU4foOWF-JdWYIYBALJH9b
|
|
9
9
|
praisonaiagents/knowledge/chunking.py,sha256=FzoNY0q8MkvG4gADqk4JcRhmH3lcEHbRdonDgitQa30,6624
|
10
10
|
praisonaiagents/knowledge/knowledge.py,sha256=fQNREDiwdoisfIxJBLVkteXgq_8Gbypfc3UaZbxf5QY,13210
|
11
11
|
praisonaiagents/llm/__init__.py,sha256=ttPQQJQq6Tah-0updoEXDZFKWtJAM93rBWRoIgxRWO8,689
|
12
|
-
praisonaiagents/llm/llm.py,sha256=
|
12
|
+
praisonaiagents/llm/llm.py,sha256=WEfqWEOb2Sa2V5MRVa2XbFCBcrE5WBMeEhSFq3HCZvM,49145
|
13
13
|
praisonaiagents/memory/memory.py,sha256=I8dOTkrl1i-GgQbDcrFOsSruzJ7MiI6Ys37DK27wrUs,35537
|
14
14
|
praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
|
15
15
|
praisonaiagents/process/process.py,sha256=_1Nk37kOYakPaUWAJff86rP0ENyykXqMnhTp8E0efuE,30802
|
@@ -35,7 +35,7 @@ praisonaiagents/tools/wikipedia_tools.py,sha256=pGko-f33wqXgxJTv8db7TbizY5XnzBQR
|
|
35
35
|
praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxNMMs1A,17122
|
36
36
|
praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
|
37
37
|
praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
|
38
|
-
praisonaiagents-0.0.
|
39
|
-
praisonaiagents-0.0.
|
40
|
-
praisonaiagents-0.0.
|
41
|
-
praisonaiagents-0.0.
|
38
|
+
praisonaiagents-0.0.52.dist-info/METADATA,sha256=NIkU1FNQXms13nIStb4r2yYjItL1aA0XSL7sCy1HxMM,830
|
39
|
+
praisonaiagents-0.0.52.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
40
|
+
praisonaiagents-0.0.52.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
41
|
+
praisonaiagents-0.0.52.dist-info/RECORD,,
|
File without changes
|
File without changes
|