PikoAi 0.1.11__py3-none-any.whl → 0.1.13__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.
- Agents/Executor/executor.py +7 -17
- Agents/Executor/prompts.py +22 -47
- Env/python_executor.py +9 -14
- Env/shell.py +28 -22
- Utils/ter_interface.py +6 -56
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/METADATA +1 -1
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/RECORD +11 -11
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/WHEEL +0 -0
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/entry_points.txt +0 -0
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/licenses/LICENSE +0 -0
- {pikoai-0.1.11.dist-info → pikoai-0.1.13.dist-info}/top_level.txt +0 -0
Agents/Executor/executor.py
CHANGED
@@ -7,7 +7,7 @@ import time
|
|
7
7
|
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../')))
|
8
8
|
from Utils.ter_interface import TerminalInterface
|
9
9
|
from Utils.executor_utils import parse_tool_call
|
10
|
-
from Agents.Executor.prompts import
|
10
|
+
from Agents.Executor.prompts import get_executor_prompt # Import prompts
|
11
11
|
|
12
12
|
from typing import Optional
|
13
13
|
from mistralai.models.sdkerror import SDKError # This might be an issue if LiteLLM doesn't use SDKError
|
@@ -22,7 +22,7 @@ from llm_interface.llm import LiteLLMInterface # Import LiteLLMInterface
|
|
22
22
|
from Tools import tool_manager
|
23
23
|
|
24
24
|
class RateLimiter:
|
25
|
-
def __init__(self, wait_time: float =
|
25
|
+
def __init__(self, wait_time: float = 1.0, max_retries: int = 3):
|
26
26
|
self.wait_time = wait_time
|
27
27
|
self.max_retries = max_retries
|
28
28
|
self.last_call_time = None
|
@@ -44,7 +44,7 @@ class executor:
|
|
44
44
|
# self.shell_executor = ShellExecutor() # Initialize ShellExecutor
|
45
45
|
self.message = [
|
46
46
|
{"role": "system", "content": self.system_prompt},
|
47
|
-
{"role": "user", "content": self.
|
47
|
+
{"role": "user", "content": self.user_prompt}
|
48
48
|
]
|
49
49
|
self.terminal = TerminalInterface()
|
50
50
|
self.initialize_llm()
|
@@ -71,8 +71,7 @@ class executor:
|
|
71
71
|
config = json.load(config_file)
|
72
72
|
working_dir = config.get("working_directory", "")
|
73
73
|
|
74
|
-
self.system_prompt =
|
75
|
-
self.task_prompt = get_task_prompt()
|
74
|
+
self.system_prompt = get_executor_prompt(working_dir, tools_details)
|
76
75
|
|
77
76
|
def run_inference(self):
|
78
77
|
retries = 0
|
@@ -112,11 +111,6 @@ class executor:
|
|
112
111
|
self.run_task()
|
113
112
|
|
114
113
|
def run_task(self):
|
115
|
-
# Remove tools_details parameter since it's in the prompt
|
116
|
-
task_message = self.task_prompt
|
117
|
-
|
118
|
-
self.message.append({"role": "user", "content": task_message})
|
119
|
-
|
120
114
|
iteration = 0
|
121
115
|
task_done = False
|
122
116
|
|
@@ -128,13 +122,13 @@ class executor:
|
|
128
122
|
if tool_call:
|
129
123
|
tool_name = tool_call['tool_name']
|
130
124
|
tool_input = tool_call['input']
|
131
|
-
|
125
|
+
|
132
126
|
|
133
127
|
# Call the tool and append the result (no confirmation or special logic)
|
134
128
|
try:
|
135
129
|
tool_output_result = tool_manager.call_tool(tool_name, tool_input)
|
136
|
-
|
137
|
-
|
130
|
+
if tool_name not in ['execute_python_code', 'execute_shell_command']:
|
131
|
+
self.terminal.tool_output_log(tool_output_result, tool_name)
|
138
132
|
self.message.append({"role": "user", "content": tool_output_result})
|
139
133
|
except ValueError as e:
|
140
134
|
error_msg = str(e)
|
@@ -142,10 +136,6 @@ class executor:
|
|
142
136
|
self.message.append({"role": "user", "content": f"Tool Error: {error_msg}"})
|
143
137
|
|
144
138
|
else: # Not a tool call, could be a direct response or requires clarification
|
145
|
-
# This part handles responses that are not formatted as tool calls.
|
146
|
-
# It might be a final answer, a question, or just conversational text.
|
147
|
-
# The existing logic for TASK_DONE or asking for next step handles this.
|
148
|
-
# No specific code/shell parsing here anymore as they are tools.
|
149
139
|
pass # Explicitly pass if no tool call and no old code/shell logic.
|
150
140
|
|
151
141
|
# Check if task is done
|
Agents/Executor/prompts.py
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
import platform
|
4
4
|
|
5
|
-
def
|
5
|
+
def get_executor_prompt(working_dir: str, tools_details: str) -> str:
|
6
6
|
"""
|
7
|
-
Returns the
|
7
|
+
Returns the main executor prompt.
|
8
8
|
"""
|
9
9
|
os_name = platform.system()
|
10
|
-
|
10
|
+
# tools_details is passed to the LLM but not directly included in this prompt string.
|
11
|
+
return f"""You are a terminal-based operating system assistant designed to help users achieve their goals.
|
11
12
|
|
13
|
+
This is important information about the environment:
|
12
14
|
Working Directory: {working_dir}
|
13
15
|
Operating System: {os_name}
|
14
16
|
|
@@ -31,53 +33,26 @@ You must break down the user's goal into smaller steps and perform one action at
|
|
31
33
|
}}
|
32
34
|
}}
|
33
35
|
<<END_TOOL_CALL>>
|
34
|
-
|
35
|
-
|
36
|
-
`execute_shell_command`: {{"command": "your_shell_command_here"}}
|
36
|
+
- **Code Execution**: Write Python code when no tool is suitable or when custom logic is needed.
|
37
|
+
the code written will be executed immediately and not saved.
|
37
38
|
- **Direct Response**: Provide a direct answer if the task doesn't require tools or code.
|
38
39
|
|
39
|
-
### Important Notes:
|
40
|
-
- Perform only one action per step.
|
41
|
-
- Always evaluate the output of each action before deciding the next step.
|
42
|
-
- Continue performing actions until the user's goal is fully achieved. Only then, include 'TASK_DONE' in your response.
|
43
|
-
- Do not end the task immediately after a tool call or code execution without evaluating its output.
|
44
|
-
|
45
|
-
Now, carefully plan your approach and start with the first step to achieve the user's goal.
|
46
|
-
"""
|
47
40
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
These are the things that you learned from the mistakes you made earlier :
|
42
|
+
- When given a data file and asked to understand data/do data analysis/ data visualisation or similar stuff
|
43
|
+
do not use file reader and read the whole data. Only use python code to do the analysis
|
44
|
+
- This is a standard Python environment, not a python notebook or a repl. previous execution
|
45
|
+
context is not preserved between executions.
|
46
|
+
- Don't execute dangerous commands like rm -rf * or access sensitive files
|
47
|
+
- If you are stuck, have tried to fix an issue (e.g., a linter error) multiple times (e.g., 3 times) without success, or need clarification, ask the USER for input. Explain the situation clearly.
|
48
|
+
- Upon creating anything (like a new project, website, data analysis png) always show the output.You can do this by executing shell commands.
|
49
|
+
- the python/shell code execution in tool call will be executed immediately and output will be shown. it wont be saved.
|
54
50
|
|
55
|
-
- For tool calls, use:
|
56
|
-
<<TOOL_CALL>>
|
57
|
-
{
|
58
|
-
"tool_name": "name_of_tool",
|
59
|
-
"input": {
|
60
|
-
"key": "value" // Use the correct parameter name for each tool
|
61
|
-
}
|
62
|
-
}
|
63
|
-
<<END_TOOL_CALL>>
|
64
|
-
Remember that executing Python code and shell commands is now done through specific tool calls (`execute_python_code` and `execute_shell_command`).
|
65
51
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
Use the working directory as the current directory for all file operations unless otherwise specified.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
These are the things that you learn't from the mistakes you made earlier :
|
76
|
-
|
77
|
-
- When given a data file and asked to understand data/do data analysis/ data visualisation or similar stuff
|
78
|
-
do not use file reader and read the whole data. Only use python code to do the analysis
|
79
|
-
- This is a standard Python environment, not a python notebook or a repl. previous execution
|
80
|
-
context is not preserved between executions.
|
81
|
-
- You have a get_user_input tool to ask user more context before, in between or after tasks
|
52
|
+
** Important **
|
53
|
+
- Perform only one action per step (either a single tool call or a single code execution).
|
54
|
+
- Always evaluate the output of each action before deciding the next step.
|
55
|
+
- Continue performing actions until the user's goal is fully achieved. Only then, include 'TASK_DONE' in your response if that is the required signal for completion.
|
56
|
+
- Do not end the task immediately after a tool call or code execution without evaluating its output.
|
82
57
|
|
83
|
-
"""
|
58
|
+
"""
|
Env/python_executor.py
CHANGED
@@ -58,7 +58,7 @@ try:
|
|
58
58
|
except Exception as e:
|
59
59
|
print(f"Error: {{str(e)}}")
|
60
60
|
"""
|
61
|
-
|
61
|
+
|
62
62
|
|
63
63
|
try:
|
64
64
|
# Execute the code in a subprocess
|
@@ -75,19 +75,14 @@ except Exception as e:
|
|
75
75
|
stderr_data = []
|
76
76
|
start_time = time.time()
|
77
77
|
|
78
|
-
#
|
79
|
-
|
80
|
-
|
81
|
-
if
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
'error': 'Timeout error'
|
87
|
-
}
|
88
|
-
|
89
|
-
stdout_data.append(line)
|
90
|
-
print(line, end='', flush=True) # Print in real-time
|
78
|
+
# Read stdout character by character
|
79
|
+
while True:
|
80
|
+
char = self.process.stdout.read(1)
|
81
|
+
if char == '' and self.process.poll() is not None:
|
82
|
+
break # Process ended and no more output
|
83
|
+
if char:
|
84
|
+
stdout_data.append(char)
|
85
|
+
print(char, end='', flush=True) # Print in real-time, no extra newline
|
91
86
|
|
92
87
|
# Then read all stderr
|
93
88
|
for line in self.process.stderr:
|
Env/shell.py
CHANGED
@@ -78,15 +78,26 @@ class ShellExecutor(BaseEnv):
|
|
78
78
|
'output': 'Blocked potentially harmful command.',
|
79
79
|
'error': f'Command matches forbidden pattern: {pattern}'
|
80
80
|
}
|
81
|
-
#
|
81
|
+
# Improved check for sensitive directory access
|
82
82
|
for sensitive_dir in sensitive_dirs:
|
83
|
-
# Only block if the command is trying to directly
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
83
|
+
# Only block if the command is trying to directly operate on the sensitive dir itself (not subpaths)
|
84
|
+
# For '/', block only if the command is exactly '/' or has a space and then '/'
|
85
|
+
if sensitive_dir == '/':
|
86
|
+
if re.search(r'(\s|^)/($|\s)', code_or_command):
|
87
|
+
return {
|
88
|
+
'success': False,
|
89
|
+
'output': f'Blocked access to sensitive directory: {sensitive_dir}',
|
90
|
+
'error': f'Attempted access to sensitive directory: {sensitive_dir}'
|
91
|
+
}
|
92
|
+
else:
|
93
|
+
# Block if the command is operating on the directory itself, not a subpath (e.g., 'ls /root' but not 'ls /root/somefile')
|
94
|
+
pattern = rf'(\s|^)({re.escape(sensitive_dir)})(\s|$)'
|
95
|
+
if re.search(pattern, code_or_command, re.IGNORECASE):
|
96
|
+
return {
|
97
|
+
'success': False,
|
98
|
+
'output': f'Blocked access to sensitive directory: {sensitive_dir}',
|
99
|
+
'error': f'Attempted access to sensitive directory: {sensitive_dir}'
|
100
|
+
}
|
90
101
|
|
91
102
|
# Execute the command in a subprocess
|
92
103
|
self.process = subprocess.Popen(
|
@@ -103,21 +114,16 @@ class ShellExecutor(BaseEnv):
|
|
103
114
|
stderr_data = []
|
104
115
|
start_time = time.time()
|
105
116
|
|
106
|
-
# First read all stdout
|
107
|
-
|
108
|
-
|
109
|
-
if
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
'error': 'Timeout error'
|
115
|
-
}
|
116
|
-
|
117
|
-
stdout_data.append(line)
|
118
|
-
print(line, end='', flush=True) # Print in real-time
|
117
|
+
# First read all stdout character by character
|
118
|
+
while True:
|
119
|
+
char = self.process.stdout.read(1)
|
120
|
+
if char == '' and self.process.poll() is not None:
|
121
|
+
break # Process ended and no more output
|
122
|
+
if char:
|
123
|
+
stdout_data.append(char)
|
124
|
+
print(char, end='', flush=True) # Print in real-time, no extra newline
|
119
125
|
|
120
|
-
# Then read all stderr
|
126
|
+
# Then read all stderr (can keep line-by-line or do char-by-char similarly)
|
121
127
|
for line in self.process.stderr:
|
122
128
|
# Check for timeout
|
123
129
|
if time.time() - start_time > 30:
|
Utils/ter_interface.py
CHANGED
@@ -51,72 +51,32 @@ class TerminalInterface:
|
|
51
51
|
|
52
52
|
def process_markdown_chunk(self, chunk):
|
53
53
|
"""
|
54
|
-
Process a chunk of markdown text, handling
|
54
|
+
Process a chunk of markdown text, handling tool calls and regular markdown.
|
55
55
|
Args:
|
56
56
|
chunk (str): A piece of markdown text to process
|
57
57
|
"""
|
58
|
-
# Initialize tracking attributes if they don't exist yet
|
59
|
-
|
60
|
-
|
61
58
|
self.buffer += chunk
|
62
59
|
while "\n" in self.buffer:
|
63
60
|
line, self.buffer = self.buffer.split("\n", 1)
|
64
61
|
line_stripped = line.strip()
|
65
|
-
|
66
|
-
# Handle code blocks
|
67
|
-
if line_stripped.startswith("<<CODE>>"):
|
68
|
-
if self.inside_code_block:
|
69
|
-
# Closing code block
|
70
|
-
self.console.print(Syntax(self.code_buffer, "python", theme="bw", line_numbers=False))
|
71
|
-
self.inside_code_block = False
|
72
|
-
self.code_buffer = ""
|
73
|
-
else:
|
74
|
-
# Opening code block
|
75
|
-
self.inside_code_block = True
|
76
|
-
self.code_lang = line_stripped[8:].strip() or "python" # default lang
|
77
|
-
|
78
|
-
# Handle shell command blocks
|
79
|
-
elif line_stripped.startswith("<<SHELL_COMMAND>>"):
|
80
|
-
self.inside_shell_command = True
|
81
|
-
self.shell_command_buffer = ""
|
82
|
-
# Print a styled header for shell commands
|
83
|
-
self.console.print("[bold yellow]Shell Command:[/bold yellow]")
|
84
|
-
|
85
|
-
elif line_stripped.startswith("<<END_SHELL_COMMAND>>"):
|
86
|
-
if self.inside_shell_command:
|
87
|
-
# Closing shell command block
|
88
|
-
self.console.print(Syntax(self.shell_command_buffer.strip(), "bash", theme="monokai", line_numbers=False))
|
89
|
-
self.inside_shell_command = False
|
90
|
-
self.shell_command_buffer = ""
|
91
|
-
|
62
|
+
|
92
63
|
# Handle tool call opening delimiter - be more flexible with whitespace
|
93
|
-
|
64
|
+
if "<<TOOL_CALL>>" in line_stripped:
|
94
65
|
self.inside_tool_call = True
|
95
66
|
self.tool_call_buffer = ""
|
96
|
-
# Print a styled header for tool calls
|
97
67
|
self.console.print("[bold cyan]Tool Call:[/bold cyan]")
|
98
|
-
|
68
|
+
|
99
69
|
# Handle tool call closing delimiter - be more flexible with whitespace
|
100
70
|
elif "<<END_TOOL_CALL>>" in line_stripped:
|
101
71
|
self.console.print(Syntax('{"status": "end_tool_call"}', "json", theme="monokai", line_numbers=False))
|
102
72
|
self.console.print("[bold cyan]--------------------------------[/bold cyan]")
|
103
73
|
self.inside_tool_call = False
|
104
74
|
self.tool_call_buffer = ""
|
105
|
-
|
106
|
-
# Handle content inside code blocks
|
107
|
-
elif self.inside_code_block:
|
108
|
-
self.code_buffer += line + "\n"
|
109
|
-
|
110
|
-
# Handle content inside shell command blocks
|
111
|
-
elif self.inside_shell_command:
|
112
|
-
self.shell_command_buffer += line + "\n"
|
113
|
-
|
75
|
+
|
114
76
|
# Handle content inside tool calls
|
115
77
|
elif self.inside_tool_call:
|
116
78
|
self.tool_call_buffer += line + "\n"
|
117
|
-
# Print the line with styling as it comes in
|
118
79
|
|
119
|
-
|
120
80
|
# Regular markdown content
|
121
81
|
else:
|
122
82
|
self.console.print(Markdown(line))
|
@@ -125,14 +85,7 @@ class TerminalInterface:
|
|
125
85
|
"""
|
126
86
|
Flush any remaining markdown content in the buffer.
|
127
87
|
"""
|
128
|
-
if self.
|
129
|
-
self.console.print(Syntax(self.code_buffer, "python", theme="bw", line_numbers=False))
|
130
|
-
self.inside_code_block = False
|
131
|
-
elif self.inside_shell_command:
|
132
|
-
self.console.print(Syntax(self.shell_command_buffer.strip(), "bash", theme="monokai", line_numbers=False))
|
133
|
-
|
134
|
-
self.inside_shell_command = False
|
135
|
-
elif hasattr(self, 'inside_tool_call') and self.inside_tool_call:
|
88
|
+
if hasattr(self, 'inside_tool_call') and self.inside_tool_call:
|
136
89
|
# Handle case where tool call is not properly terminated
|
137
90
|
self.console.print(Syntax(self.tool_call_buffer.strip(), "json", theme="monokai", line_numbers=False))
|
138
91
|
self.console.print("[bold cyan]End Tool Call (forced)[/bold cyan]")
|
@@ -142,10 +95,7 @@ class TerminalInterface:
|
|
142
95
|
self.console.print("━" * 80) # Print a solid line
|
143
96
|
else:
|
144
97
|
self.console.print(Markdown(self.buffer))
|
145
|
-
|
146
98
|
self.buffer = ""
|
147
|
-
self.code_buffer = ""
|
148
|
-
self.shell_command_buffer = ""
|
149
99
|
if hasattr(self, 'tool_call_buffer'):
|
150
100
|
self.tool_call_buffer = ""
|
151
101
|
|
@@ -2,15 +2,15 @@ OpenCopilot.py,sha256=vBAuU6MNhYdnyIIrDWOBSlxa0iyjADJLq5eCxUhlffw,12240
|
|
2
2
|
cli.py,sha256=hY6KUxvKvJOFThZT--r6m2nzOEMIOVtiVptewsi9Z9w,13868
|
3
3
|
Agents/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
4
|
Agents/Executor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
-
Agents/Executor/executor.py,sha256
|
6
|
-
Agents/Executor/prompts.py,sha256=
|
5
|
+
Agents/Executor/executor.py,sha256=-HvywqfroHd0QYNt5AN8vV7wjR-91hWPbSuvNzIVMMU,8191
|
6
|
+
Agents/Executor/prompts.py,sha256=dWmUiAloNN_NKwWgaG_IqHDhCX1O-VhwbadUL-16gZw,2903
|
7
7
|
Env/__init__.py,sha256=KLe7UcNV5L395SxhMwbYGyu7KPrSNaoV_9QJo3mLop0,196
|
8
8
|
Env/base_env.py,sha256=K4PoWwPXn3pKeu7_-JOlUuyNbyYQ9itMhQybFOm-3K4,1563
|
9
9
|
Env/base_executor.py,sha256=awTwJ44CKWV4JO2KUHfHDX0p1Ujw55hlaL5oNYTEW9M,893
|
10
10
|
Env/env.py,sha256=I3lOoyBJR5QNq3tWk_HVH6ncRx1vnilRYmj7b7h4jic,114
|
11
11
|
Env/js_executor.py,sha256=tEAg5ho8Pa8LzxUbS1Idau8XuJWZZqPiNlvFPDwGkgc,2690
|
12
|
-
Env/python_executor.py,sha256=
|
13
|
-
Env/shell.py,sha256=
|
12
|
+
Env/python_executor.py,sha256=siiR-BivXKlCHoL6Jyb3aSQkHdZXCFMNo3c3rspHllA,4664
|
13
|
+
Env/shell.py,sha256=DuttZymCUM7QNRxIOPBB81bSBcgzH-wQdUADYridRTo,7987
|
14
14
|
Env/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
15
15
|
Env/tests/test_python_executor.py,sha256=5kfs0cOf-RgWTOers_1wB0yvYSF-HrHPsraJ-PxgR50,3156
|
16
16
|
Env/tests/test_shell_executor.py,sha256=-RcCdSUMoRAXHISIh0IR5MCutco80fX2S3sQBcinc_Q,1034
|
@@ -24,12 +24,12 @@ Tools/web_loader.py,sha256=PyZk2g7WngZT0tCLs9Danx20dYspnaZwy4rlVE9Sx_4,5054
|
|
24
24
|
Tools/web_search.py,sha256=4EGq1VZqfDgG-_yXTd4_Ha1iEUcR-szdlgRV7oFPru4,1259
|
25
25
|
Utils/__init__.py,sha256=oukU0ufroPRd8_N8d2xiFes9CTxSaw4NA6p2nS1kkSg,16
|
26
26
|
Utils/executor_utils.py,sha256=WwK3TKgw_hG_crg7ijRaqfidYnnNXYbbs37vKZRYK-0,491
|
27
|
-
Utils/ter_interface.py,sha256=
|
27
|
+
Utils/ter_interface.py,sha256=2k32kVxcxVBewXnjSGSPbx25ZLhKindEMtL6wSC_wL4,3829
|
28
28
|
llm_interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
29
29
|
llm_interface/llm.py,sha256=tI_KDOW14QLWowA7bB3GPe2qjlk0sjS5fBavs9XD1fo,5185
|
30
|
-
pikoai-0.1.
|
31
|
-
pikoai-0.1.
|
32
|
-
pikoai-0.1.
|
33
|
-
pikoai-0.1.
|
34
|
-
pikoai-0.1.
|
35
|
-
pikoai-0.1.
|
30
|
+
pikoai-0.1.13.dist-info/licenses/LICENSE,sha256=cELUVOboOAderKFp8bdtcM5VyJi61YH1oDbRhOuoQZw,1067
|
31
|
+
pikoai-0.1.13.dist-info/METADATA,sha256=mjc1I8aWnP9tMaG0Mlvme1AX-dgDIul3ugC5C5yxbXc,2962
|
32
|
+
pikoai-0.1.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
33
|
+
pikoai-0.1.13.dist-info/entry_points.txt,sha256=xjZnheDymNDnQ0o84R0jZKEITrhNbzQWN-AhqfA_d6s,50
|
34
|
+
pikoai-0.1.13.dist-info/top_level.txt,sha256=hWzBNE7UQsuNcENIOksGcJED08k3ZGRRn2X5jnStICU,53
|
35
|
+
pikoai-0.1.13.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|