praisonaiagents 0.0.54__py3-none-any.whl → 0.0.57__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 +132 -63
- praisonaiagents/llm/llm.py +25 -6
- praisonaiagents/process/process.py +8 -4
- praisonaiagents/tools/__init__.py +22 -1
- praisonaiagents/tools/train/data/generatecot.py +493 -0
- {praisonaiagents-0.0.54.dist-info → praisonaiagents-0.0.57.dist-info}/METADATA +1 -1
- {praisonaiagents-0.0.54.dist-info → praisonaiagents-0.0.57.dist-info}/RECORD +9 -8
- {praisonaiagents-0.0.54.dist-info → praisonaiagents-0.0.57.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.54.dist-info → praisonaiagents-0.0.57.dist-info}/top_level.txt +0 -0
praisonaiagents/agent/agent.py
CHANGED
@@ -97,36 +97,79 @@ def process_stream_chunks(chunks):
|
|
97
97
|
|
98
98
|
content_list = []
|
99
99
|
reasoning_list = []
|
100
|
+
tool_calls = []
|
101
|
+
current_tool_call = None
|
100
102
|
|
103
|
+
# First pass: Get initial tool call data
|
101
104
|
for chunk in chunks:
|
102
105
|
if not hasattr(chunk, "choices") or not chunk.choices:
|
103
106
|
continue
|
104
107
|
|
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
108
|
delta = getattr(chunk.choices[0], "delta", None)
|
111
109
|
if not delta:
|
112
110
|
continue
|
113
|
-
|
111
|
+
|
112
|
+
# Handle content and reasoning
|
114
113
|
if hasattr(delta, "content") and delta.content:
|
115
114
|
content_list.append(delta.content)
|
116
115
|
if hasattr(delta, "reasoning_content") and delta.reasoning_content:
|
117
116
|
reasoning_list.append(delta.reasoning_content)
|
117
|
+
|
118
|
+
# Handle tool calls
|
119
|
+
if hasattr(delta, "tool_calls") and delta.tool_calls:
|
120
|
+
for tool_call_delta in delta.tool_calls:
|
121
|
+
if tool_call_delta.index is not None and tool_call_delta.id:
|
122
|
+
# Found the initial tool call
|
123
|
+
current_tool_call = {
|
124
|
+
"id": tool_call_delta.id,
|
125
|
+
"type": "function",
|
126
|
+
"function": {
|
127
|
+
"name": tool_call_delta.function.name,
|
128
|
+
"arguments": ""
|
129
|
+
}
|
130
|
+
}
|
131
|
+
while len(tool_calls) <= tool_call_delta.index:
|
132
|
+
tool_calls.append(None)
|
133
|
+
tool_calls[tool_call_delta.index] = current_tool_call
|
134
|
+
current_tool_call = tool_calls[tool_call_delta.index]
|
135
|
+
elif current_tool_call is not None and hasattr(tool_call_delta.function, "arguments"):
|
136
|
+
if tool_call_delta.function.arguments:
|
137
|
+
current_tool_call["function"]["arguments"] += tool_call_delta.function.arguments
|
138
|
+
|
139
|
+
# Remove any None values and empty tool calls
|
140
|
+
tool_calls = [tc for tc in tool_calls if tc and tc["id"] and tc["function"]["name"]]
|
118
141
|
|
119
142
|
combined_content = "".join(content_list) if content_list else ""
|
120
143
|
combined_reasoning = "".join(reasoning_list) if reasoning_list else None
|
121
144
|
finish_reason = getattr(last_chunk.choices[0], "finish_reason", None) if hasattr(last_chunk, "choices") and last_chunk.choices else None
|
122
145
|
|
146
|
+
# Create ToolCall objects
|
147
|
+
processed_tool_calls = []
|
148
|
+
if tool_calls:
|
149
|
+
try:
|
150
|
+
from openai.types.chat import ChatCompletionMessageToolCall
|
151
|
+
for tc in tool_calls:
|
152
|
+
tool_call = ChatCompletionMessageToolCall(
|
153
|
+
id=tc["id"],
|
154
|
+
type=tc["type"],
|
155
|
+
function={
|
156
|
+
"name": tc["function"]["name"],
|
157
|
+
"arguments": tc["function"]["arguments"]
|
158
|
+
}
|
159
|
+
)
|
160
|
+
processed_tool_calls.append(tool_call)
|
161
|
+
except Exception as e:
|
162
|
+
print(f"Error processing tool call: {e}")
|
163
|
+
|
123
164
|
message = ChatCompletionMessage(
|
124
165
|
content=combined_content,
|
125
|
-
|
166
|
+
role="assistant",
|
167
|
+
reasoning_content=combined_reasoning,
|
168
|
+
tool_calls=processed_tool_calls if processed_tool_calls else None
|
126
169
|
)
|
127
170
|
|
128
171
|
choice = Choice(
|
129
|
-
finish_reason=finish_reason,
|
172
|
+
finish_reason=finish_reason or "tool_calls" if processed_tool_calls else None,
|
130
173
|
index=0,
|
131
174
|
message=message
|
132
175
|
)
|
@@ -528,6 +571,53 @@ Your Goal: {self.goal}
|
|
528
571
|
def __str__(self):
|
529
572
|
return f"Agent(name='{self.name}', role='{self.role}', goal='{self.goal}')"
|
530
573
|
|
574
|
+
def _process_stream_response(self, messages, temperature, start_time, formatted_tools=None, reasoning_steps=False):
|
575
|
+
"""Process streaming response and return final response"""
|
576
|
+
try:
|
577
|
+
# Create the response stream
|
578
|
+
response_stream = client.chat.completions.create(
|
579
|
+
model=self.llm,
|
580
|
+
messages=messages,
|
581
|
+
temperature=temperature,
|
582
|
+
tools=formatted_tools if formatted_tools else None,
|
583
|
+
stream=True
|
584
|
+
)
|
585
|
+
|
586
|
+
full_response_text = ""
|
587
|
+
reasoning_content = ""
|
588
|
+
chunks = []
|
589
|
+
|
590
|
+
# Create Live display with proper configuration
|
591
|
+
with Live(
|
592
|
+
display_generating("", start_time),
|
593
|
+
console=self.console,
|
594
|
+
refresh_per_second=4,
|
595
|
+
transient=True,
|
596
|
+
vertical_overflow="ellipsis",
|
597
|
+
auto_refresh=True
|
598
|
+
) as live:
|
599
|
+
for chunk in response_stream:
|
600
|
+
chunks.append(chunk)
|
601
|
+
if chunk.choices[0].delta.content:
|
602
|
+
full_response_text += chunk.choices[0].delta.content
|
603
|
+
live.update(display_generating(full_response_text, start_time))
|
604
|
+
|
605
|
+
# Update live display with reasoning content if enabled
|
606
|
+
if reasoning_steps and hasattr(chunk.choices[0].delta, "reasoning_content"):
|
607
|
+
rc = chunk.choices[0].delta.reasoning_content
|
608
|
+
if rc:
|
609
|
+
reasoning_content += rc
|
610
|
+
live.update(display_generating(f"{full_response_text}\n[Reasoning: {reasoning_content}]", start_time))
|
611
|
+
|
612
|
+
# Clear the last generating display with a blank line
|
613
|
+
self.console.print()
|
614
|
+
final_response = process_stream_chunks(chunks)
|
615
|
+
return final_response
|
616
|
+
|
617
|
+
except Exception as e:
|
618
|
+
display_error(f"Error in stream processing: {e}")
|
619
|
+
return None
|
620
|
+
|
531
621
|
def _chat_completion(self, messages, temperature=0.2, tools=None, stream=True, reasoning_steps=False):
|
532
622
|
start_time = time.time()
|
533
623
|
logging.debug(f"{self.name} sending messages to LLM: {messages}")
|
@@ -554,20 +644,31 @@ Your Goal: {self.goal}
|
|
554
644
|
logging.warning(f"Tool {tool} not recognized")
|
555
645
|
|
556
646
|
try:
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
647
|
+
if stream:
|
648
|
+
# Process as streaming response with formatted tools
|
649
|
+
final_response = self._process_stream_response(
|
650
|
+
messages,
|
651
|
+
temperature,
|
652
|
+
start_time,
|
653
|
+
formatted_tools=formatted_tools if formatted_tools else None,
|
654
|
+
reasoning_steps=reasoning_steps
|
655
|
+
)
|
656
|
+
else:
|
657
|
+
# Process as regular non-streaming response
|
658
|
+
final_response = client.chat.completions.create(
|
659
|
+
model=self.llm,
|
660
|
+
messages=messages,
|
661
|
+
temperature=temperature,
|
662
|
+
tools=formatted_tools if formatted_tools else None,
|
663
|
+
stream=False
|
664
|
+
)
|
564
665
|
|
565
|
-
tool_calls = getattr(
|
666
|
+
tool_calls = getattr(final_response.choices[0].message, 'tool_calls', None)
|
566
667
|
|
567
668
|
if tool_calls:
|
568
669
|
messages.append({
|
569
|
-
"role": "assistant",
|
570
|
-
"content":
|
670
|
+
"role": "assistant",
|
671
|
+
"content": final_response.choices[0].message.content,
|
571
672
|
"tool_calls": tool_calls
|
572
673
|
})
|
573
674
|
|
@@ -590,55 +691,24 @@ Your Goal: {self.goal}
|
|
590
691
|
"content": results_str
|
591
692
|
})
|
592
693
|
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
# Create Live display with proper configuration
|
605
|
-
with Live(
|
606
|
-
display_generating("", start_time),
|
607
|
-
console=self.console,
|
608
|
-
refresh_per_second=4,
|
609
|
-
transient=True,
|
610
|
-
vertical_overflow="ellipsis",
|
611
|
-
auto_refresh=True
|
612
|
-
) as live:
|
613
|
-
for chunk in response_stream:
|
614
|
-
chunks.append(chunk)
|
615
|
-
if chunk.choices[0].delta.content:
|
616
|
-
full_response_text += chunk.choices[0].delta.content
|
617
|
-
live.update(display_generating(full_response_text, start_time))
|
618
|
-
|
619
|
-
# Update live display with reasoning content if enabled
|
620
|
-
if reasoning_steps 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))
|
625
|
-
|
626
|
-
# Clear the last generating display with a blank line
|
627
|
-
self.console.print()
|
628
|
-
|
629
|
-
final_response = process_stream_chunks(chunks)
|
630
|
-
return final_response
|
631
|
-
else:
|
632
|
-
if tool_calls:
|
694
|
+
# Get final response after tool calls
|
695
|
+
if stream:
|
696
|
+
final_response = self._process_stream_response(
|
697
|
+
messages,
|
698
|
+
temperature,
|
699
|
+
start_time,
|
700
|
+
formatted_tools=formatted_tools if formatted_tools else None,
|
701
|
+
reasoning_steps=reasoning_steps
|
702
|
+
)
|
703
|
+
else:
|
633
704
|
final_response = client.chat.completions.create(
|
634
705
|
model=self.llm,
|
635
706
|
messages=messages,
|
636
707
|
temperature=temperature,
|
637
708
|
stream=False
|
638
709
|
)
|
639
|
-
|
640
|
-
|
641
|
-
return initial_response
|
710
|
+
|
711
|
+
return final_response
|
642
712
|
|
643
713
|
except Exception as e:
|
644
714
|
display_error(f"Error in chat completion: {e}")
|
@@ -758,8 +828,7 @@ Your Goal: {self.goal}
|
|
758
828
|
|
759
829
|
tool_calls = getattr(response.choices[0].message, 'tool_calls', None)
|
760
830
|
response_text = response.choices[0].message.content.strip()
|
761
|
-
|
762
|
-
if tool_calls:
|
831
|
+
if tool_calls: ## TODO: Most likely this tool call is already called in _chat_completion, so maybe we can remove this.
|
763
832
|
messages.append({
|
764
833
|
"role": "assistant",
|
765
834
|
"content": response_text,
|
praisonaiagents/llm/llm.py
CHANGED
@@ -17,6 +17,8 @@ from ..main import (
|
|
17
17
|
from rich.console import Console
|
18
18
|
from rich.live import Live
|
19
19
|
|
20
|
+
# TODO: Include in-build tool calling in LLM class
|
21
|
+
# TODO: Restructure so that duplicate calls are not made (Sync with agent.py)
|
20
22
|
class LLMContextLengthExceededException(Exception):
|
21
23
|
"""Raised when LLM context length is exceeded"""
|
22
24
|
def __init__(self, message: str):
|
@@ -111,11 +113,28 @@ class LLM:
|
|
111
113
|
litellm.success_callback = []
|
112
114
|
litellm._async_success_callback = []
|
113
115
|
litellm.callbacks = []
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
|
117
|
+
verbose = extra_settings.get('verbose', True)
|
118
|
+
|
119
|
+
# Only suppress logs if not in debug mode
|
120
|
+
if not isinstance(verbose, bool) and verbose >= 10:
|
121
|
+
# Enable detailed debug logging
|
122
|
+
logging.getLogger("asyncio").setLevel(logging.DEBUG)
|
123
|
+
logging.getLogger("selector_events").setLevel(logging.DEBUG)
|
124
|
+
logging.getLogger("litellm.utils").setLevel(logging.DEBUG)
|
125
|
+
logging.getLogger("litellm.main").setLevel(logging.DEBUG)
|
126
|
+
litellm.suppress_debug_messages = False
|
127
|
+
litellm.set_verbose = True
|
128
|
+
else:
|
129
|
+
# Suppress debug logging for normal operation
|
130
|
+
logging.getLogger("asyncio").setLevel(logging.WARNING)
|
131
|
+
logging.getLogger("selector_events").setLevel(logging.WARNING)
|
132
|
+
logging.getLogger("litellm.utils").setLevel(logging.WARNING)
|
133
|
+
logging.getLogger("litellm.main").setLevel(logging.WARNING)
|
134
|
+
litellm.suppress_debug_messages = True
|
135
|
+
litellm._logging._disable_debugging()
|
136
|
+
warnings.filterwarnings("ignore", category=RuntimeWarning)
|
137
|
+
|
119
138
|
except ImportError:
|
120
139
|
raise ImportError(
|
121
140
|
"LiteLLM is required but not installed. "
|
@@ -143,7 +162,7 @@ class LLM:
|
|
143
162
|
self.extra_settings = extra_settings
|
144
163
|
self.console = Console()
|
145
164
|
self.chat_history = []
|
146
|
-
self.verbose =
|
165
|
+
self.verbose = verbose
|
147
166
|
self.markdown = extra_settings.get('markdown', True)
|
148
167
|
self.self_reflect = extra_settings.get('self_reflect', False)
|
149
168
|
self.max_reflect = extra_settings.get('max_reflect', 3)
|
@@ -44,6 +44,8 @@ class Process:
|
|
44
44
|
current_task = start_task
|
45
45
|
visited_tasks = set()
|
46
46
|
loop_data = {} # Store loop-specific data
|
47
|
+
|
48
|
+
# TODO: start task with loop feature is not available in aworkflow method
|
47
49
|
|
48
50
|
while current_task:
|
49
51
|
current_iter += 1
|
@@ -350,9 +352,10 @@ Provide a JSON with the structure:
|
|
350
352
|
if row: # Skip empty rows
|
351
353
|
task_desc = row[0] # Take first column
|
352
354
|
row_task = Task(
|
353
|
-
description=task_desc
|
355
|
+
description=f"{start_task.description}\n{task_desc}" if start_task.description else task_desc,
|
354
356
|
agent=start_task.agent,
|
355
|
-
name=
|
357
|
+
name=f"{start_task.name}_{i+1}" if start_task.name else task_desc,
|
358
|
+
expected_output=getattr(start_task, 'expected_output', None),
|
356
359
|
is_start=(i == 0),
|
357
360
|
task_type="task",
|
358
361
|
condition={
|
@@ -374,9 +377,10 @@ Provide a JSON with the structure:
|
|
374
377
|
previous_task = None
|
375
378
|
for i, line in enumerate(lines):
|
376
379
|
row_task = Task(
|
377
|
-
description=line.strip(),
|
380
|
+
description=f"{start_task.description}\n{line.strip()}" if start_task.description else line.strip(),
|
378
381
|
agent=start_task.agent,
|
379
|
-
name=line.strip(),
|
382
|
+
name=f"{start_task.name}_{i+1}" if start_task.name else line.strip(),
|
383
|
+
expected_output=getattr(start_task, 'expected_output', None),
|
380
384
|
is_start=(i == 0),
|
381
385
|
task_type="task",
|
382
386
|
condition={
|
@@ -135,6 +135,27 @@ TOOL_MAPPINGS = {
|
|
135
135
|
'group_by': ('.pandas_tools', 'PandasTools'),
|
136
136
|
'pivot_table': ('.pandas_tools', 'PandasTools'),
|
137
137
|
'pandas_tools': ('.pandas_tools', 'PandasTools'),
|
138
|
+
|
139
|
+
# Chain of Thought Training Tools
|
140
|
+
'cot_run': ('.train.data.generatecot', 'GenerateCOT'), # Orchestrates text solution
|
141
|
+
'cot_run_dict': ('.train.data.generatecot', 'GenerateCOT'), # Orchestrates dict-based solution
|
142
|
+
'cot_generate': ('.train.data.generatecot', 'GenerateCOT'), # Generate text solution
|
143
|
+
'cot_generate_dict': ('.train.data.generatecot', 'GenerateCOT'), # Generate structured solution
|
144
|
+
'cot_improve': ('.train.data.generatecot', 'GenerateCOT'), # Improve text solution
|
145
|
+
'cot_improve_dict': ('.train.data.generatecot', 'GenerateCOT'), # Improve dict-based solution
|
146
|
+
'cot_check': ('.train.data.generatecot', 'GenerateCOT'), # Check correctness
|
147
|
+
'cot_find_error': ('.train.data.generatecot', 'GenerateCOT'), # Locate error in solution
|
148
|
+
'cot_load_answers': ('.train.data.generatecot', 'GenerateCOT'), # Load QA pairs
|
149
|
+
|
150
|
+
# COT Save/Export with QA Pairs
|
151
|
+
'cot_save_solutions_with_qa_pairs': ('.train.data.generatecot', 'GenerateCOT'), # Save with QA pairs
|
152
|
+
'cot_append_solutions_with_qa_pairs': ('.train.data.generatecot', 'GenerateCOT'), # Append with QA pairs
|
153
|
+
'cot_export_json_with_qa_pairs': ('.train.data.generatecot', 'GenerateCOT'), # Export JSON with QA pairs
|
154
|
+
'cot_export_csv_with_qa_pairs': ('.train.data.generatecot', 'GenerateCOT'), # Export CSV with QA pairs
|
155
|
+
'cot_append_csv_with_qa_pairs': ('.train.data.generatecot', 'GenerateCOT'), # Append CSV with QA pairs
|
156
|
+
'cot_save': ('.train.data.generatecot', 'GenerateCOT'), # Save single QA to file
|
157
|
+
'cot_upload_to_huggingface': ('.train.data.generatecot', 'GenerateCOT'), # Upload dataset to HuggingFace
|
158
|
+
'cot_tools': ('.train.data.generatecot', 'GenerateCOT'), # Full toolkit access
|
138
159
|
}
|
139
160
|
|
140
161
|
_instances = {} # Cache for class instances
|
@@ -161,7 +182,7 @@ def __getattr__(name: str) -> Any:
|
|
161
182
|
]:
|
162
183
|
return getattr(module, name)
|
163
184
|
if name in ['file_tools', 'pandas_tools', 'wikipedia_tools',
|
164
|
-
'newspaper_tools', 'arxiv_tools', 'spider_tools', 'duckdb_tools', 'csv_tools', 'json_tools', 'excel_tools', 'xml_tools', 'yaml_tools', 'calculator_tools', 'python_tools', 'shell_tools']:
|
185
|
+
'newspaper_tools', 'arxiv_tools', 'spider_tools', 'duckdb_tools', 'csv_tools', 'json_tools', 'excel_tools', 'xml_tools', 'yaml_tools', 'calculator_tools', 'python_tools', 'shell_tools', 'cot_tools']:
|
165
186
|
return module # Returns the callable module
|
166
187
|
return getattr(module, name)
|
167
188
|
else:
|
@@ -0,0 +1,493 @@
|
|
1
|
+
from typing import Dict, Optional, Union, Any
|
2
|
+
import json
|
3
|
+
from datetime import datetime
|
4
|
+
from openai import OpenAI
|
5
|
+
from pydantic import BaseModel
|
6
|
+
|
7
|
+
# Lazy loader for LLM
|
8
|
+
def get_llm():
|
9
|
+
try:
|
10
|
+
from praisonaiagents.llm.llm import LLM
|
11
|
+
return LLM
|
12
|
+
except ImportError:
|
13
|
+
raise ImportError(
|
14
|
+
"LLM is required for this toolbut not installed. "
|
15
|
+
"Please install with: pip install 'praisonaiagents[llm]' datasets huggingface-hub pandas"
|
16
|
+
)
|
17
|
+
|
18
|
+
class GenerateCOT:
|
19
|
+
def __init__(
|
20
|
+
self,
|
21
|
+
qa_pairs: Optional[Dict[str, str]] = None,
|
22
|
+
model: str = "gpt-4o-mini",
|
23
|
+
api_key: Optional[str] = None,
|
24
|
+
max_attempts: int = 100
|
25
|
+
):
|
26
|
+
self.qa_pairs = qa_pairs or {}
|
27
|
+
self.max_attempts = max_attempts
|
28
|
+
self.solutions = {}
|
29
|
+
self.llm = get_llm()(model=model) # Get LLM class and instantiate
|
30
|
+
self.model = model
|
31
|
+
|
32
|
+
def _ask_ai(self, prompt: str) -> str:
|
33
|
+
return self.llm.get_response(prompt, temperature=0.7)
|
34
|
+
|
35
|
+
def _build_solution_prompt(self, question: str, context: str) -> str:
|
36
|
+
return f"""
|
37
|
+
Solve this problem step by step: {question}
|
38
|
+
Context: {context}
|
39
|
+
Steps needed:
|
40
|
+
1. Break down the problem
|
41
|
+
2. Show your work
|
42
|
+
3. Explain each step
|
43
|
+
4. Give final answer
|
44
|
+
"""
|
45
|
+
|
46
|
+
def cot_generate(self, question: str, context: str = "") -> str:
|
47
|
+
prompt = self._build_solution_prompt(question, context)
|
48
|
+
return self._ask_ai(prompt)
|
49
|
+
|
50
|
+
def cot_check(self, question: str, answer: str) -> bool:
|
51
|
+
if question not in self.qa_pairs:
|
52
|
+
raise ValueError(f"No correct answer found for: {question}")
|
53
|
+
|
54
|
+
prompt = f"""
|
55
|
+
Question: {question}
|
56
|
+
Given Answer: {answer}
|
57
|
+
Correct Answer: {self.qa_pairs[question]}
|
58
|
+
Is the given answer correct? Reply only with 'true' or 'false'.
|
59
|
+
"""
|
60
|
+
return self._ask_ai(prompt).lower().strip() == "true"
|
61
|
+
|
62
|
+
def cot_find_error(self, question: str, solution: str) -> int:
|
63
|
+
if self.cot_check(question, solution):
|
64
|
+
return -1
|
65
|
+
|
66
|
+
sentences = [s.strip() for s in solution.replace('。', '.').split('.') if s.strip()]
|
67
|
+
left, right = 0, len(sentences)
|
68
|
+
|
69
|
+
while left < right:
|
70
|
+
mid = (left + right) // 2
|
71
|
+
partial = '. '.join(sentences[:mid]) + '.'
|
72
|
+
if self.cot_check(question, partial):
|
73
|
+
left = mid + 1
|
74
|
+
else:
|
75
|
+
right = mid
|
76
|
+
|
77
|
+
return left
|
78
|
+
|
79
|
+
def cot_improve(self, question: str, current: str) -> str:
|
80
|
+
best_solution = current
|
81
|
+
best_score = self._rate_solution(question, current)
|
82
|
+
|
83
|
+
for _ in range(self.max_attempts):
|
84
|
+
new_solution = self.cot_generate(question, current)
|
85
|
+
new_score = self._rate_solution(question, new_solution)
|
86
|
+
|
87
|
+
if new_score > best_score:
|
88
|
+
best_solution = new_solution
|
89
|
+
best_score = new_score
|
90
|
+
|
91
|
+
if best_score > 0.9:
|
92
|
+
break
|
93
|
+
|
94
|
+
return best_solution
|
95
|
+
|
96
|
+
def _rate_solution(self, question: str, solution: str) -> float:
|
97
|
+
prompt = f"""
|
98
|
+
Rate this solution from 0 to 1:
|
99
|
+
Question: {question}
|
100
|
+
Solution: {solution}
|
101
|
+
Correct Answer: {self.qa_pairs.get(question, '')}
|
102
|
+
Return only a number between 0 and 1.
|
103
|
+
"""
|
104
|
+
try:
|
105
|
+
score = float(self._ask_ai(prompt))
|
106
|
+
return min(max(score, 0), 1)
|
107
|
+
except:
|
108
|
+
return 0.0
|
109
|
+
|
110
|
+
def cot_run(self, question: str) -> str:
|
111
|
+
"""Run COT generation for a single question."""
|
112
|
+
solution = self.cot_generate(question)
|
113
|
+
if self.cot_check(question, solution):
|
114
|
+
return solution
|
115
|
+
|
116
|
+
solution = self.cot_improve(question, solution)
|
117
|
+
|
118
|
+
error_pos = self.cot_find_error(question, solution)
|
119
|
+
if error_pos != -1:
|
120
|
+
correct_part = '. '.join(solution.split('. ')[:error_pos]) + '.'
|
121
|
+
solution = self.cot_generate(question, correct_part)
|
122
|
+
|
123
|
+
self.solutions[question] = {
|
124
|
+
"solution": solution,
|
125
|
+
"error_position": error_pos,
|
126
|
+
}
|
127
|
+
return solution
|
128
|
+
|
129
|
+
def cot_load_answers(self, filepath: str) -> bool:
|
130
|
+
try:
|
131
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
132
|
+
data = json.load(f)
|
133
|
+
self.qa_pairs.update(data)
|
134
|
+
return True
|
135
|
+
except Exception as e:
|
136
|
+
print(f"Error loading answers: {e}")
|
137
|
+
return False
|
138
|
+
|
139
|
+
def _is_qa_pairs(self, qa_pairs: Any) -> bool:
|
140
|
+
"""Validate if input is a proper QA pairs dictionary."""
|
141
|
+
if not qa_pairs:
|
142
|
+
return True # None or empty is valid
|
143
|
+
if not isinstance(qa_pairs, dict):
|
144
|
+
raise ValueError("qa_pairs must be a dictionary with questions as keys and answers as values")
|
145
|
+
return True
|
146
|
+
|
147
|
+
def cot_append_solutions_with_qa_pairs(
|
148
|
+
self,
|
149
|
+
filepath: str = 'solutions.json',
|
150
|
+
qa_pairs: Optional[Dict[str, str]] = None
|
151
|
+
) -> None:
|
152
|
+
"""Appends current solutions to existing file or creates a new one."""
|
153
|
+
try:
|
154
|
+
self._is_qa_pairs(qa_pairs) # Validate format
|
155
|
+
if qa_pairs:
|
156
|
+
self.qa_pairs.update(qa_pairs)
|
157
|
+
|
158
|
+
data = {
|
159
|
+
"solutions": self.solutions,
|
160
|
+
"qa_pairs": self.qa_pairs,
|
161
|
+
"saved_at": datetime.now().isoformat()
|
162
|
+
}
|
163
|
+
|
164
|
+
existing_data = {}
|
165
|
+
try:
|
166
|
+
with open(filepath, 'r', encoding='utf-8') as f:
|
167
|
+
existing_data = json.load(f)
|
168
|
+
except (FileNotFoundError, json.JSONDecodeError):
|
169
|
+
pass
|
170
|
+
|
171
|
+
if existing_data:
|
172
|
+
existing_data["solutions"].update(data["solutions"])
|
173
|
+
existing_data["qa_pairs"].update(data["qa_pairs"])
|
174
|
+
existing_data["saved_at"] = data["saved_at"]
|
175
|
+
data = existing_data
|
176
|
+
|
177
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
178
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
179
|
+
except Exception as e:
|
180
|
+
print(f"Error appending solutions: {e}")
|
181
|
+
|
182
|
+
def cot_save_solutions_with_qa_pairs(
|
183
|
+
self,
|
184
|
+
filepath: str = 'solutions.json',
|
185
|
+
append: bool = False,
|
186
|
+
qa_pairs: Optional[Dict[str, str]] = None
|
187
|
+
) -> None:
|
188
|
+
try:
|
189
|
+
self._is_qa_pairs(qa_pairs) # Validate format
|
190
|
+
if qa_pairs:
|
191
|
+
self.qa_pairs.update(qa_pairs)
|
192
|
+
|
193
|
+
if append:
|
194
|
+
self.cot_append_solutions_with_qa_pairs(filepath)
|
195
|
+
return
|
196
|
+
|
197
|
+
data = {
|
198
|
+
"solutions": self.solutions,
|
199
|
+
"qa_pairs": self.qa_pairs,
|
200
|
+
"saved_at": datetime.now().isoformat()
|
201
|
+
}
|
202
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
203
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
204
|
+
except Exception as e:
|
205
|
+
print(f"Error saving solutions: {e}")
|
206
|
+
|
207
|
+
def cot_generate_dict(self, question: str, context: str = "") -> dict:
|
208
|
+
prompt = self._build_solution_prompt(question, context)
|
209
|
+
thought_process = self._ask_ai(prompt)
|
210
|
+
|
211
|
+
final_answer_prompt = f"""
|
212
|
+
Based on this solution, what is the final answer only:
|
213
|
+
{thought_process}
|
214
|
+
Give only the final answer, no explanation.
|
215
|
+
"""
|
216
|
+
final_answer = self._ask_ai(final_answer_prompt)
|
217
|
+
return {
|
218
|
+
"thought_process": thought_process,
|
219
|
+
"final_answer": final_answer
|
220
|
+
}
|
221
|
+
|
222
|
+
def cot_improve_dict(self, question: str, current_solution: str) -> dict:
|
223
|
+
"""
|
224
|
+
Improves the existing solution (text form), returning the best dictionary-based version.
|
225
|
+
"""
|
226
|
+
best_solution = {
|
227
|
+
"thought_process": current_solution,
|
228
|
+
"final_answer": current_solution
|
229
|
+
}
|
230
|
+
best_score = self._rate_solution(question, current_solution)
|
231
|
+
|
232
|
+
for _ in range(self.max_attempts):
|
233
|
+
new_solution = self.cot_generate_dict(question, current_solution)
|
234
|
+
new_score = self._rate_solution(question, new_solution["thought_process"])
|
235
|
+
if new_score > best_score:
|
236
|
+
best_solution = new_solution
|
237
|
+
best_score = new_score
|
238
|
+
if best_score > 0.9:
|
239
|
+
break
|
240
|
+
return best_solution
|
241
|
+
|
242
|
+
def cot_run_dict(self, question: str) -> dict:
|
243
|
+
"""Uses the dictionary-based solution approach, storing the final solution in self.solutions."""
|
244
|
+
solution = self.cot_generate_dict(question)
|
245
|
+
if self.cot_check(question, solution["final_answer"]):
|
246
|
+
self.solutions[question] = solution
|
247
|
+
return solution
|
248
|
+
|
249
|
+
improved = self.cot_improve_dict(question, solution["thought_process"])
|
250
|
+
if self.cot_check(question, improved["final_answer"]):
|
251
|
+
self.solutions[question] = improved
|
252
|
+
return improved
|
253
|
+
|
254
|
+
error_pos = self.cot_find_error(question, improved["thought_process"])
|
255
|
+
if error_pos != -1:
|
256
|
+
partial_solution = '. '.join(improved["thought_process"].split('. ')[:error_pos]) + '.'
|
257
|
+
final = self.cot_generate_dict(question, partial_solution)
|
258
|
+
self.solutions[question] = final
|
259
|
+
return final
|
260
|
+
|
261
|
+
self.solutions[question] = improved
|
262
|
+
return improved
|
263
|
+
|
264
|
+
def cot_export_json_with_qa_pairs(
|
265
|
+
self,
|
266
|
+
filepath: str = 'dataset.json',
|
267
|
+
save_to_file: bool = True,
|
268
|
+
qa_pairs: Optional[Dict[str, str]] = None
|
269
|
+
) -> Union[str, list]:
|
270
|
+
"""
|
271
|
+
Export solutions in Alpaca training format with their full thought process.
|
272
|
+
"""
|
273
|
+
try:
|
274
|
+
self._is_qa_pairs(qa_pairs) # Validate format
|
275
|
+
if qa_pairs:
|
276
|
+
self.qa_pairs.update(qa_pairs)
|
277
|
+
# Generate solutions if empty
|
278
|
+
if not self.solutions:
|
279
|
+
for question in qa_pairs:
|
280
|
+
self.cot_run_dict(question)
|
281
|
+
|
282
|
+
alpaca_data = []
|
283
|
+
for question, sol in self.solutions.items():
|
284
|
+
alpaca_data.append({
|
285
|
+
"instruction": question,
|
286
|
+
"input": "",
|
287
|
+
"output": sol.get("thought_process", "")
|
288
|
+
})
|
289
|
+
|
290
|
+
if not save_to_file:
|
291
|
+
return alpaca_data
|
292
|
+
|
293
|
+
with open(filepath, 'w', encoding='utf-8') as f:
|
294
|
+
json.dump(alpaca_data, f, ensure_ascii=False, indent=2)
|
295
|
+
return filepath
|
296
|
+
except Exception as e:
|
297
|
+
print(f"Error exporting to Alpaca format: {e}")
|
298
|
+
return None
|
299
|
+
|
300
|
+
def cot_export_csv_with_qa_pairs(
|
301
|
+
self,
|
302
|
+
filepath: str = 'dataset.csv',
|
303
|
+
qa_pairs: Optional[Dict[str, str]] = None
|
304
|
+
) -> Optional[str]:
|
305
|
+
"""Export solutions in CSV format."""
|
306
|
+
try:
|
307
|
+
self._is_qa_pairs(qa_pairs) # Validate format
|
308
|
+
if qa_pairs:
|
309
|
+
self.qa_pairs.update(qa_pairs)
|
310
|
+
# Generate solutions if empty
|
311
|
+
if not self.solutions:
|
312
|
+
for question in qa_pairs:
|
313
|
+
self.cot_run_dict(question)
|
314
|
+
|
315
|
+
with open(filepath, 'w', newline='', encoding='utf-8') as f:
|
316
|
+
writer = csv.writer(f)
|
317
|
+
writer.writerow(['instruction', 'input', 'output'])
|
318
|
+
for question, sol in self.solutions.items():
|
319
|
+
writer.writerow([question, '', sol.get("thought_process", "")])
|
320
|
+
return filepath
|
321
|
+
except Exception as e:
|
322
|
+
print(f"Error exporting to CSV format: {e}")
|
323
|
+
return None
|
324
|
+
|
325
|
+
def cot_save(
|
326
|
+
self,
|
327
|
+
question: str,
|
328
|
+
answer: str,
|
329
|
+
filepath: str = 'dataset.csv'
|
330
|
+
) -> Optional[str]:
|
331
|
+
"""
|
332
|
+
Save a single question-answer pair with chain of thought to CSV file.
|
333
|
+
Creates file with headers if it doesn't exist.
|
334
|
+
"""
|
335
|
+
try:
|
336
|
+
# Remove timestamp-based filename generation since we have default
|
337
|
+
solution = self.cot_run_dict(question)
|
338
|
+
|
339
|
+
import csv
|
340
|
+
import os
|
341
|
+
file_exists = os.path.exists(filepath)
|
342
|
+
|
343
|
+
with open(filepath, 'a', newline='', encoding='utf-8') as f:
|
344
|
+
writer = csv.writer(f)
|
345
|
+
if not file_exists:
|
346
|
+
writer.writerow(['instruction', 'input', 'output'])
|
347
|
+
writer.writerow([question, '', solution.get("thought_process", "")])
|
348
|
+
return filepath
|
349
|
+
except Exception as e:
|
350
|
+
print(f"Error appending to CSV: {e}")
|
351
|
+
return None
|
352
|
+
|
353
|
+
# Rename existing function to indicate it handles qa_pairs dictionary
|
354
|
+
def cot_append_csv_with_qa_pairs(
|
355
|
+
self,
|
356
|
+
filepath: str = 'dataset.csv',
|
357
|
+
qa_pairs: Optional[Dict[str, str]] = None
|
358
|
+
) -> Optional[str]:
|
359
|
+
"""Append solutions to CSV file using qa_pairs dictionary."""
|
360
|
+
try:
|
361
|
+
self._is_qa_pairs(qa_pairs) # Validate format
|
362
|
+
if qa_pairs:
|
363
|
+
self.qa_pairs.update(qa_pairs)
|
364
|
+
|
365
|
+
import csv
|
366
|
+
import os
|
367
|
+
file_exists = os.path.exists(filepath)
|
368
|
+
|
369
|
+
with open(filepath, 'a', newline='', encoding='utf-8') as f:
|
370
|
+
writer = csv.writer(f)
|
371
|
+
if not file_exists:
|
372
|
+
writer.writerow(['instruction', 'input', 'output'])
|
373
|
+
|
374
|
+
for question, sol in self.solutions.items():
|
375
|
+
writer.writerow([question, '', sol.get("thought_process", "")])
|
376
|
+
return filepath
|
377
|
+
except Exception as e:
|
378
|
+
print(f"Error appending to CSV: {e}")
|
379
|
+
return None
|
380
|
+
|
381
|
+
def cot_upload_to_huggingface(
|
382
|
+
self,
|
383
|
+
huggingface_username: str,
|
384
|
+
dataset_name: str,
|
385
|
+
filepath: str,
|
386
|
+
private: bool = False
|
387
|
+
) -> str:
|
388
|
+
"""Upload generated solutions to HuggingFace datasets."""
|
389
|
+
try:
|
390
|
+
from datasets import Dataset
|
391
|
+
from huggingface_hub import HfApi, login
|
392
|
+
import pandas as pd
|
393
|
+
|
394
|
+
# Determine file type and load data
|
395
|
+
if filepath.endswith('.csv'):
|
396
|
+
data = pd.read_csv(filepath)
|
397
|
+
elif filepath.endswith('.json'):
|
398
|
+
data = pd.read_json(filepath)
|
399
|
+
else:
|
400
|
+
raise ValueError("Only CSV and JSON files are supported")
|
401
|
+
|
402
|
+
# Convert to HuggingFace dataset
|
403
|
+
dataset = Dataset.from_pandas(data)
|
404
|
+
|
405
|
+
# Upload to HuggingFace
|
406
|
+
repo_id = f"{huggingface_username}/{dataset_name}"
|
407
|
+
dataset.push_to_hub(
|
408
|
+
repo_id,
|
409
|
+
private=private
|
410
|
+
)
|
411
|
+
|
412
|
+
return f"Dataset uploaded successfully to {repo_id}"
|
413
|
+
|
414
|
+
except Exception as e:
|
415
|
+
print(f"Error uploading to HuggingFace: {e}")
|
416
|
+
return None
|
417
|
+
|
418
|
+
# Usage example:
|
419
|
+
if __name__ == "__main__":
|
420
|
+
# Direct QA Pairs Export Example
|
421
|
+
print("\n=== Direct QA Pairs Export Example ===")
|
422
|
+
direct_qa_data = {
|
423
|
+
"Number of r's in the word strawberry": "3"
|
424
|
+
}
|
425
|
+
|
426
|
+
direct_generator = GenerateCOT()
|
427
|
+
|
428
|
+
# Export with qa_pairs passed directly to functions
|
429
|
+
direct_generator.cot_export_csv_with_qa_pairs(
|
430
|
+
filepath='direct_solutions.csv',
|
431
|
+
qa_pairs=direct_qa_data
|
432
|
+
)
|
433
|
+
|
434
|
+
# Example of using cot_save for a single QA pair
|
435
|
+
direct_generator.cot_save(
|
436
|
+
question="What is the capital of France?",
|
437
|
+
answer="Paris",
|
438
|
+
filepath="single_qa.csv"
|
439
|
+
)
|
440
|
+
|
441
|
+
|
442
|
+
|
443
|
+
# Upload to HuggingFace
|
444
|
+
direct_generator.cot_upload_to_huggingface(
|
445
|
+
huggingface_username="mervinpraison",
|
446
|
+
dataset_name="cot-test",
|
447
|
+
filepath="single_qa.csv"
|
448
|
+
)
|
449
|
+
|
450
|
+
# direct_generator.cot_export_json_with_qa_pairs(
|
451
|
+
# filepath='direct_solutions.json',
|
452
|
+
# qa_pairs=direct_qa_data
|
453
|
+
# )
|
454
|
+
|
455
|
+
# # Rest of the original examples...
|
456
|
+
# qa_data = {
|
457
|
+
# "What is 2+2?": "4",
|
458
|
+
# "How many letters in 'hello'?": "5"
|
459
|
+
# }
|
460
|
+
|
461
|
+
# generator = GenerateCOT(qa_pairs=qa_data)
|
462
|
+
# for question in qa_data:
|
463
|
+
# solution = generator.cot_run(question)
|
464
|
+
# print(f"Question: {question}")
|
465
|
+
# print(f"Solution: {solution}\n")
|
466
|
+
# answer = generator.cot_run("What is 2+2?")
|
467
|
+
# print(answer)
|
468
|
+
|
469
|
+
# # Additional QA data processing example
|
470
|
+
# print("\n=== Processing Additional QA Data ===")
|
471
|
+
# extra_qa_data = {
|
472
|
+
|
473
|
+
# "What is 5 * 3?": "15"
|
474
|
+
# }
|
475
|
+
|
476
|
+
# # Create separate generator for additional data
|
477
|
+
# extra_generator = GenerateCOT(qa_pairs=extra_qa_data)
|
478
|
+
|
479
|
+
# # Process and save solutions
|
480
|
+
# for question in extra_qa_data:
|
481
|
+
# solution = extra_generator.cot_run_dict(question)
|
482
|
+
# print(f"Processing extra question: {question}")
|
483
|
+
|
484
|
+
# # Save solutions separately
|
485
|
+
# extra_generator.cot_save_solutions_with_qa_pairs('extra_qa_solutions.json')
|
486
|
+
|
487
|
+
# # Export in Alpaca format
|
488
|
+
# extra_generator.cot_export_json_with_qa_pairs(filepath='extra_qa_alpaca.json', save_to_file=True)
|
489
|
+
|
490
|
+
# # Demonstrate loading saved data
|
491
|
+
# loaded_generator = GenerateCOT(qa_pairs={})
|
492
|
+
# loaded_generator.cot_load_answers('extra_qa_solutions.json')
|
493
|
+
# print("\nLoaded extra QA pairs:", loaded_generator.qa_pairs)
|
@@ -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=VZPci7g_LAvTz7_rWvWAZ1JgCGKQc1vSfI6x0fqi2os,57598
|
5
5
|
praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
|
6
6
|
praisonaiagents/agents/agents.py,sha256=94YPQl-hl-EPY6-Xk2Rj9wlIs9YtiLQbsutSOXWX8QI,36156
|
7
7
|
praisonaiagents/agents/autoagents.py,sha256=bjC2O5oZmoJItJXIMPTWc2lsp_AJC9tMiTQOal2hwPA,13532
|
@@ -9,13 +9,13 @@ 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=G2wKMwitWBJRS6nOq9W77zXtsxvJwsVwXFOKYcllY0E,51386
|
13
13
|
praisonaiagents/memory/memory.py,sha256=I8dOTkrl1i-GgQbDcrFOsSruzJ7MiI6Ys37DK27wrUs,35537
|
14
14
|
praisonaiagents/process/__init__.py,sha256=lkYbL7Hn5a0ldvJtkdH23vfIIZLIcanK-65C0MwaorY,52
|
15
|
-
praisonaiagents/process/process.py,sha256=
|
15
|
+
praisonaiagents/process/process.py,sha256=gP3QQxxFO4oUw_HYLf8MoyWyaj_104LIL_AbwLiBxaU,31261
|
16
16
|
praisonaiagents/task/__init__.py,sha256=VL5hXVmyGjINb34AalxpBMl-YW9m5EDcRkMTKkSSl7c,80
|
17
17
|
praisonaiagents/task/task.py,sha256=ikFjzNm4WPYONSLtWA3uDGNIUx_TvXTeU5SukWoC66E,14271
|
18
|
-
praisonaiagents/tools/__init__.py,sha256
|
18
|
+
praisonaiagents/tools/__init__.py,sha256=CWOYV9SudYY82r45LnNgaVRV3cmsAFdasNRkPrLsgmI,9198
|
19
19
|
praisonaiagents/tools/arxiv_tools.py,sha256=1stb31zTjLTon4jCnpZG5de9rKc9QWgC0leLegvPXWo,10528
|
20
20
|
praisonaiagents/tools/calculator_tools.py,sha256=S1xPT74Geurvjm52QMMIG29zDXVEWJmM6nmyY7yF298,9571
|
21
21
|
praisonaiagents/tools/csv_tools.py,sha256=gX2nYz4ktmpKvXB36jx5-GqddntEQD4G2fVQWTIKrwU,8435
|
@@ -35,7 +35,8 @@ 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
|
39
|
-
praisonaiagents-0.0.
|
40
|
-
praisonaiagents-0.0.
|
41
|
-
praisonaiagents-0.0.
|
38
|
+
praisonaiagents/tools/train/data/generatecot.py,sha256=HA8HwbhGIavfALxMbKTdGwABP5S6qzuiPtmUiV-FTZI,17491
|
39
|
+
praisonaiagents-0.0.57.dist-info/METADATA,sha256=ad3iyUlLBQqjpuTcbka6Z6MAX57RaJGRbkifyYEhz-w,830
|
40
|
+
praisonaiagents-0.0.57.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
41
|
+
praisonaiagents-0.0.57.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
42
|
+
praisonaiagents-0.0.57.dist-info/RECORD,,
|
File without changes
|
File without changes
|