Compare commits

...
3 Commits
Author SHA1 Message Date
Mervin Praison a970e849b4 Release v2.3.87 2025-12-23 16:08:35 +00:00
Mervin Praison 8e68f4e71c Release v2.3.86 2025-12-23 15:23:31 +00:00
Mervin Praison 308758cdc2 Release v2.3.85 2025-12-23 15:07:46 +00:00
13 changed files with 90 additions and 59 deletions

No files matched your search

+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.3.84" \
"praisonai>=2.3.87" \
"praisonai[chat]" \
"embedchain[github,youtube]"
+1 -1
View File
@@ -20,7 +20,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.3.84" \
"praisonai>=2.3.87" \
"praisonai[ui]" \
"praisonai[chat]" \
"praisonai[realtime]" \
+1 -1
View File
@@ -16,7 +16,7 @@ RUN mkdir -p /root/.praison
# Install Python packages (using latest versions)
RUN pip install --no-cache-dir \
praisonai_tools \
"praisonai>=2.3.84" \
"praisonai>=2.3.87" \
"praisonai[ui]" \
"praisonai[crewai]"
@@ -28,20 +28,31 @@ def format_skill_for_prompt(skill: SkillMetadata) -> str:
</skill>"""
def generate_skills_xml(skills: List[SkillMetadata]) -> str:
def generate_skills_xml(skills: List[SkillMetadata], working_directory: str = None) -> str:
"""Generate XML block for available skills.
Args:
skills: List of SkillMetadata instances
working_directory: Current working directory for path resolution
Returns:
XML string with <available_skills> block
"""
import os
cwd = working_directory or os.getcwd()
if not skills:
return "<available_skills>\n</available_skills>"
return f"""<available_skills>
<working_directory>{html.escape(cwd)}</working_directory>
<note>When using run_skill_script, pass file paths relative to the working directory or as absolute paths. The tool will resolve relative paths automatically.</note>
</available_skills>"""
skill_entries = "\n".join(format_skill_for_prompt(s) for s in skills)
return f"<available_skills>\n{skill_entries}\n</available_skills>"
return f"""<available_skills>
<working_directory>{html.escape(cwd)}</working_directory>
<note>When using run_skill_script, pass file paths relative to the working directory or as absolute paths. The tool will resolve relative paths automatically.</note>
{skill_entries}
</available_skills>"""
def to_prompt(skill_dirs: List[Path]) -> str:
@@ -6,7 +6,7 @@ files and optional scripts.
Usage:
from praisonaiagents.tools import run_skill_script
result = run_skill_script("./my-skill/scripts/script.py", "./data.csv")
result = run_skill_script("./my-skill/scripts/skill.py", "./data.csv")
"""
import subprocess
@@ -46,7 +46,7 @@ class SkillTools:
Execute a skill script from a skill's scripts/ directory.
Args:
script_path: Path to the script file (e.g., ./csv-analyzer/scripts/script.py)
script_path: Path to the script file (e.g., ./csv-analyzer/scripts/skill.py)
args: Arguments to pass to the script (e.g., file path to analyze)
timeout: Maximum execution time in seconds (default: 60)
@@ -67,17 +67,20 @@ class SkillTools:
resolved_args = []
if args:
for arg in args.split():
# If arg looks like a file path, resolve it
if arg.startswith('./') or arg.startswith('../') or (
not arg.startswith('-') and '/' in arg or '.' in arg
):
potential_path = os.path.join(self._working_directory, arg)
if os.path.exists(potential_path):
resolved_args.append(os.path.abspath(potential_path))
else:
# Keep original arg if path doesn't exist
resolved_args.append(arg)
# Skip flags
if arg.startswith('-'):
resolved_args.append(arg)
continue
# Try to resolve as a path relative to working directory
potential_path = os.path.join(self._working_directory, arg)
if os.path.exists(potential_path):
resolved_args.append(os.path.abspath(potential_path))
elif os.path.isabs(arg) and os.path.exists(arg):
# Already absolute and exists
resolved_args.append(arg)
else:
# Keep original arg if path doesn't exist
resolved_args.append(arg)
# Determine how to run the script based on extension
@@ -131,7 +134,7 @@ class SkillTools:
Args:
skill_path: Path to the skill directory (e.g., ./csv-analyzer)
file_path: Relative path within the skill (e.g., SKILL.md, scripts/script.py)
file_path: Relative path within the skill (e.g., SKILL.md, scripts/skill.py)
encoding: File encoding (default: utf-8)
Returns:
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.1.25"
version = "0.1.27"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
readme = "README.md"
requires-python = ">=3.10"
+1 -1
View File
@@ -2422,7 +2422,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.1.25"
version = "0.1.27"
source = { editable = "." }
dependencies = [
{ name = "aiohttp" },
+2 -2
View File
@@ -3,8 +3,8 @@ class Praisonai < Formula
desc "AI tools for various AI applications"
homepage "https://github.com/MervinPraison/PraisonAI"
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.84.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.84.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.87.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.87.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
+46 -29
View File
@@ -165,14 +165,14 @@ class SkillsHandler:
(skill_dir / "SKILL.md").write_text(skill_md_content)
# Generate scripts/script.py if requested or AI provided it
# Generate scripts/skill.py if requested or AI provided it
if generate_script or (ai_content and ai_content.get("skill_py")):
script_content = (ai_content or {}).get("skill_py") or self._generate_template_script(name, description)
# Strip any remaining code blocks from script content
script_content = self._strip_code_blocks(script_content)
(skill_dir / "scripts" / "script.py").write_text(script_content)
(skill_dir / "scripts" / "skill.py").write_text(script_content)
if self.verbose:
print(" - scripts/script.py")
print(" - scripts/skill.py")
else:
(skill_dir / "scripts" / ".gitkeep").write_text("")
@@ -207,18 +207,18 @@ class SkillsHandler:
script_section = f"""
## Script Usage
This skill includes a Python script at `scripts/script.py` that provides the core functionality.
This skill includes a Python script at `scripts/skill.py` that provides the core functionality.
### Running the Script
```bash
python scripts/script.py <input>
python scripts/skill.py <input>
```
### Using as a Module
```python
from scripts.script import {func_name}
from scripts.skill import {func_name}
result = {func_name}(input_data)
print(result)
@@ -253,7 +253,7 @@ Describe how to use this skill.
"""
def _generate_template_script(self, name: str, description: str) -> str:
"""Generate description-relevant scripts/script.py content."""
"""Generate description-relevant scripts/skill.py content."""
func_name = name.replace('-', '_')
# Analyze description to generate relevant code
@@ -297,6 +297,19 @@ Describe how to use this skill.
This script provides functionality for the {name} skill.
"""
import sys
import json
import pandas as pd
def json_serializer(obj):
"""Handle numpy types for JSON serialization."""
if hasattr(obj, 'item'):
return obj.item()
elif hasattr(obj, 'tolist'):
return obj.tolist()
return str(obj)
def {func_name}(file_path: str) -> dict:
"""
@@ -308,16 +321,14 @@ def {func_name}(file_path: str) -> dict:
Returns:
Dictionary with analysis results
"""
import pandas as pd
df = pd.read_csv(file_path)
result = {{
"rows": len(df),
"columns": len(df.columns),
"rows": int(len(df)),
"columns": int(len(df.columns)),
"column_names": list(df.columns),
"dtypes": {{col: str(dtype) for col, dtype in df.dtypes.items()}},
"missing_values": df.isnull().sum().to_dict(),
"missing_values": {{k: int(v) for k, v in df.isnull().sum().to_dict().items()}},
"numeric_summary": {{}}
}}
@@ -325,7 +336,7 @@ def {func_name}(file_path: str) -> dict:
for col in numeric_cols:
result["numeric_summary"][col] = {{
"mean": float(df[col].mean()),
"std": float(df[col].std()),
"std": float(df[col].std()) if len(df) > 1 else 0.0,
"min": float(df[col].min()),
"max": float(df[col].max())
}}
@@ -335,14 +346,11 @@ def {func_name}(file_path: str) -> dict:
def main():
"""Main entry point for the skill."""
import sys
import json
if len(sys.argv) > 1:
result = {func_name}(sys.argv[1])
print(json.dumps(result, indent=2))
print(json.dumps(result, indent=2, default=json_serializer))
else:
print("Usage: python script.py <csv_file>")
print("Usage: python skill.py <csv_file>")
if __name__ == "__main__":
@@ -351,27 +359,27 @@ if __name__ == "__main__":
def _generate_pdf_script(self, name: str, description: str, func_name: str) -> str:
"""Generate PDF processing script."""
return f'''"""\n{name} - {description}\n\nThis script provides PDF processing functionality.\n"""\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process PDF file and extract content.\n \n Args:\n file_path: Path to the PDF file\n \n Returns:\n Dictionary with extracted content\n """\n from pypdf import PdfReader\n \n reader = PdfReader(file_path)\n \n result = {{\n "pages": len(reader.pages),\n "metadata": {{\n "title": reader.metadata.title if reader.metadata else None,\n "author": reader.metadata.author if reader.metadata else None\n }},\n "text": []\n }}\n \n for i, page in enumerate(reader.pages):\n result["text"].append({{\n "page": i + 1,\n "content": page.extract_text()\n }})\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <pdf_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides PDF processing functionality.\n"""\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process PDF file and extract content.\n \n Args:\n file_path: Path to the PDF file\n \n Returns:\n Dictionary with extracted content\n """\n from pypdf import PdfReader\n \n reader = PdfReader(file_path)\n \n result = {{\n "pages": len(reader.pages),\n "metadata": {{\n "title": reader.metadata.title if reader.metadata else None,\n "author": reader.metadata.author if reader.metadata else None\n }},\n "text": []\n }}\n \n for i, page in enumerate(reader.pages):\n result["text"].append({{\n "page": i + 1,\n "content": page.extract_text()\n }})\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <pdf_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_api_script(self, name: str, description: str, func_name: str) -> str:
"""Generate API/HTTP request script."""
return f'''"""\n{name} - {description}\n\nThis script provides API request functionality.\n"""\nimport requests\n\ndef {func_name}(url: str, method: str = "GET", data: dict = None) -> dict:\n """\n Make HTTP request to API endpoint.\n \n Args:\n url: API endpoint URL\n method: HTTP method (GET, POST, PUT, DELETE)\n data: Optional request body data\n \n Returns:\n Dictionary with response data\n """\n headers = {{"Content-Type": "application/json"}}\n \n if method.upper() == "GET":\n response = requests.get(url, headers=headers)\n elif method.upper() == "POST":\n response = requests.post(url, json=data, headers=headers)\n elif method.upper() == "PUT":\n response = requests.put(url, json=data, headers=headers)\n elif method.upper() == "DELETE":\n response = requests.delete(url, headers=headers)\n else:\n raise ValueError(f"Unsupported method: {{method}}")\n \n return {{\n "status_code": response.status_code,\n "headers": dict(response.headers),\n "data": response.json() if response.headers.get("content-type", "").startswith("application/json") else response.text\n }}\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <url>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides API request functionality.\n"""\nimport requests\n\ndef {func_name}(url: str, method: str = "GET", data: dict = None) -> dict:\n """\n Make HTTP request to API endpoint.\n \n Args:\n url: API endpoint URL\n method: HTTP method (GET, POST, PUT, DELETE)\n data: Optional request body data\n \n Returns:\n Dictionary with response data\n """\n headers = {{"Content-Type": "application/json"}}\n \n if method.upper() == "GET":\n response = requests.get(url, headers=headers)\n elif method.upper() == "POST":\n response = requests.post(url, json=data, headers=headers)\n elif method.upper() == "PUT":\n response = requests.put(url, json=data, headers=headers)\n elif method.upper() == "DELETE":\n response = requests.delete(url, headers=headers)\n else:\n raise ValueError(f"Unsupported method: {{method}}")\n \n return {{\n "status_code": response.status_code,\n "headers": dict(response.headers),\n "data": response.json() if response.headers.get("content-type", "").startswith("application/json") else response.text\n }}\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <url>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_file_script(self, name: str, description: str, func_name: str) -> str:
"""Generate file processing script."""
return f'''"""\n{name} - {description}\n\nThis script provides file processing functionality.\n"""\nfrom pathlib import Path\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process file and return information.\n \n Args:\n file_path: Path to the file to process\n \n Returns:\n Dictionary with file information and content\n """\n path = Path(file_path)\n \n if not path.exists():\n raise FileNotFoundError(f"File not found: {{file_path}}")\n \n stat = path.stat()\n \n result = {{\n "name": path.name,\n "extension": path.suffix,\n "size_bytes": stat.st_size,\n "is_file": path.is_file(),\n "is_dir": path.is_dir()\n }}\n \n if path.is_file() and stat.st_size < 1024 * 1024:\n try:\n result["content"] = path.read_text()\n result["lines"] = len(result["content"].splitlines())\n except UnicodeDecodeError:\n result["content"] = "<binary file>"\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <file_path>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides file processing functionality.\n"""\nfrom pathlib import Path\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process file and return information.\n \n Args:\n file_path: Path to the file to process\n \n Returns:\n Dictionary with file information and content\n """\n path = Path(file_path)\n \n if not path.exists():\n raise FileNotFoundError(f"File not found: {{file_path}}")\n \n stat = path.stat()\n \n result = {{\n "name": path.name,\n "extension": path.suffix,\n "size_bytes": stat.st_size,\n "is_file": path.is_file(),\n "is_dir": path.is_dir()\n }}\n \n if path.is_file() and stat.st_size < 1024 * 1024:\n try:\n result["content"] = path.read_text()\n result["lines"] = len(result["content"].splitlines())\n except UnicodeDecodeError:\n result["content"] = "<binary file>"\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <file_path>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_image_script(self, name: str, description: str, func_name: str) -> str:
"""Generate image processing script."""
return f'''"""\n{name} - {description}\n\nThis script provides image processing functionality.\n"""\nfrom PIL import Image\n\ndef {func_name}(file_path: str, output_path: str = None, resize: tuple = None) -> dict:\n """\n Process image file.\n \n Args:\n file_path: Path to the image file\n output_path: Optional output path for processed image\n resize: Optional tuple (width, height) to resize\n \n Returns:\n Dictionary with image information\n """\n img = Image.open(file_path)\n \n result = {{\n "format": img.format,\n "mode": img.mode,\n "size": img.size,\n "width": img.width,\n "height": img.height\n }}\n \n if resize:\n img = img.resize(resize)\n result["resized_to"] = resize\n \n if output_path:\n img.save(output_path)\n result["saved_to"] = output_path\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <image_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides image processing functionality.\n"""\nfrom PIL import Image\n\ndef {func_name}(file_path: str, output_path: str = None, resize: tuple = None) -> dict:\n """\n Process image file.\n \n Args:\n file_path: Path to the image file\n output_path: Optional output path for processed image\n resize: Optional tuple (width, height) to resize\n \n Returns:\n Dictionary with image information\n """\n img = Image.open(file_path)\n \n result = {{\n "format": img.format,\n "mode": img.mode,\n "size": img.size,\n "width": img.width,\n "height": img.height\n }}\n \n if resize:\n img = img.resize(resize)\n result["resized_to"] = resize\n \n if output_path:\n img.save(output_path)\n result["saved_to"] = output_path\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <image_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_json_script(self, name: str, description: str, func_name: str) -> str:
"""Generate JSON/YAML processing script."""
return f'''"""\n{name} - {description}\n\nThis script provides JSON/YAML processing functionality.\n"""\nimport json\nfrom pathlib import Path\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process JSON or YAML file.\n \n Args:\n file_path: Path to the JSON/YAML file\n \n Returns:\n Dictionary with parsed content and metadata\n """\n path = Path(file_path)\n content = path.read_text()\n \n if path.suffix in [".yaml", ".yml"]:\n import yaml\n data = yaml.safe_load(content)\n else:\n data = json.loads(content)\n \n result = {{\n "file": file_path,\n "format": "yaml" if path.suffix in [".yaml", ".yml"] else "json",\n "keys": list(data.keys()) if isinstance(data, dict) else None,\n "length": len(data) if isinstance(data, (list, dict)) else None,\n "data": data\n }}\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <json_or_yaml_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides JSON/YAML processing functionality.\n"""\nimport json\nfrom pathlib import Path\n\ndef {func_name}(file_path: str) -> dict:\n """\n Process JSON or YAML file.\n \n Args:\n file_path: Path to the JSON/YAML file\n \n Returns:\n Dictionary with parsed content and metadata\n """\n path = Path(file_path)\n content = path.read_text()\n \n if path.suffix in [".yaml", ".yml"]:\n import yaml\n data = yaml.safe_load(content)\n else:\n data = json.loads(content)\n \n result = {{\n "file": file_path,\n "format": "yaml" if path.suffix in [".yaml", ".yml"] else "json",\n "keys": list(data.keys()) if isinstance(data, dict) else None,\n "length": len(data) if isinstance(data, (list, dict)) else None,\n "data": data\n }}\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n \n if len(sys.argv) > 1:\n result = {func_name}(sys.argv[1])\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <json_or_yaml_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_text_script(self, name: str, description: str, func_name: str) -> str:
"""Generate text processing script."""
return f'''"""\n{name} - {description}\n\nThis script provides text processing functionality.\n"""\nimport re\n\ndef {func_name}(text: str, pattern: str = None, replacement: str = None) -> dict:\n """\n Process text with optional regex operations.\n \n Args:\n text: Input text to process\n pattern: Optional regex pattern to search\n replacement: Optional replacement string\n \n Returns:\n Dictionary with processing results\n """\n result = {{\n "original_length": len(text),\n "lines": len(text.splitlines()),\n "words": len(text.split()),\n "characters": len(text.replace(" ", ""))\n }}\n \n if pattern:\n matches = re.findall(pattern, text)\n result["matches"] = matches\n result["match_count"] = len(matches)\n \n if replacement is not None:\n result["replaced_text"] = re.sub(pattern, replacement, text)\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n with open(sys.argv[1]) as f:\n text = f.read()\n result = {func_name}(text)\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python script.py <text_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
return f'''"""\n{name} - {description}\n\nThis script provides text processing functionality.\n"""\nimport re\n\ndef {func_name}(text: str, pattern: str = None, replacement: str = None) -> dict:\n """\n Process text with optional regex operations.\n \n Args:\n text: Input text to process\n pattern: Optional regex pattern to search\n replacement: Optional replacement string\n \n Returns:\n Dictionary with processing results\n """\n result = {{\n "original_length": len(text),\n "lines": len(text.splitlines()),\n "words": len(text.split()),\n "characters": len(text.replace(" ", ""))\n }}\n \n if pattern:\n matches = re.findall(pattern, text)\n result["matches"] = matches\n result["match_count"] = len(matches)\n \n if replacement is not None:\n result["replaced_text"] = re.sub(pattern, replacement, text)\n \n return result\n\n\ndef main():\n """Main entry point for the skill."""\n import sys\n import json\n \n if len(sys.argv) > 1:\n with open(sys.argv[1]) as f:\n text = f.read()\n result = {func_name}(text)\n print(json.dumps(result, indent=2))\n else:\n print("Usage: python skill.py <text_file>")\n\n\nif __name__ == "__main__":\n main()\n'''
def _generate_generic_script(self, name: str, description: str, func_name: str) -> str:
"""Generate generic script template."""
@@ -402,7 +410,7 @@ def main():
result = {func_name}(sys.argv[1])
print(result)
else:
print("Usage: python script.py <input>")
print("Usage: python skill.py <input>")
if __name__ == "__main__":
@@ -477,17 +485,26 @@ metadata:
Generate detailed, practical content based on the description. Make it comprehensive but concise.
The skill should be immediately useful for an AI agent.
Also, if this skill requires any Python code to function, provide a script.py that implements the core functionality.
Also, if this skill requires any Python code to function, provide a skill.py that implements the core functionality.
The script MUST follow this pattern:
1. Have a main function that accepts file path as command line argument (sys.argv[1])
2. Print JSON output using json.dumps()
2. Print JSON output using json.dumps() with a custom default handler for numpy types
3. Include usage message if no arguments provided
4. Convert numpy types to native Python types (int, float) before JSON serialization
Example script pattern:
```python
import sys
import json
def json_serializer(obj):
\"\"\"Handle numpy types for JSON serialization.\"\"\"
if hasattr(obj, 'item'):
return obj.item()
elif hasattr(obj, 'tolist'):
return obj.tolist()
return str(obj)
def process_file(file_path: str) -> dict:
# Core logic here
return {{"result": "data"}}
@@ -495,9 +512,9 @@ def process_file(file_path: str) -> dict:
def main():
if len(sys.argv) > 1:
result = process_file(sys.argv[1])
print(json.dumps(result, indent=2))
print(json.dumps(result, indent=2, default=json_serializer))
else:
print("Usage: python script.py <file_path>")
print("Usage: python skill.py <file_path>")
if __name__ == "__main__":
main()
+1 -1
View File
@@ -57,7 +57,7 @@ class CloudDeployer:
file.write("FROM python:3.11-slim\n")
file.write("WORKDIR /app\n")
file.write("COPY . .\n")
file.write("RUN pip install flask praisonai==2.3.84 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.3.87 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+1 -1
View File
@@ -1 +1 @@
__version__ = "2.3.84"
__version__ = "2.3.87"
+1 -1
View File
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.1.25",
"praisonaiagents>=0.1.27",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
+4 -4
View File
@@ -4197,7 +4197,7 @@ requires-dist = [
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'autogen-v4'", specifier = ">=0.0.22" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.22" },
{ name = "praisonaiagents", specifier = ">=0.1.25" },
{ name = "praisonaiagents", specifier = ">=0.1.27" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = "==0.2.29" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -4252,7 +4252,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.1.25"
version = "0.1.27"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -4261,9 +4261,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/55/77/94bcdab12d08f43ca9cc0de9a37bf7583dfb3fff72e9e0b0d220aaa208c7/praisonaiagents-0.1.25.tar.gz", hash = "sha256:4219654e73d3352ef1b7c042c51e00a6902390970b825692f23460d877e89530", size = 681211, upload-time = "2025-12-23T14:56:09.308Z" }
sdist = { url = "https://files.pythonhosted.org/packages/ea/46/f17a1f26f1bd9cc340f276b8eb7001cb66e2132b48d6a25109beac7b3721/praisonaiagents-0.1.27.tar.gz", hash = "sha256:ec2cb07cc1fd940e107eb16ecf46494a3613e47735e9668de986876f1e043e5f", size = 681432, upload-time = "2025-12-23T16:07:37.204Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/c5/28/0c50fbb51cb13a5243d12a01ca0624ada486e5daee5d417b9b58054024c5/praisonaiagents-0.1.25-py3-none-any.whl", hash = "sha256:fae71e1052aa471e1e7f42e0bd21b08f6da37fd596b4809abd5ea0f1f2eb78f2", size = 620078, upload-time = "2025-12-23T14:56:07.211Z" },
{ url = "https://files.pythonhosted.org/packages/b8/aa/90aebc654e4a7cc02b5a0fdf108c6c64d374c3385eb0dcde6118a8ce3b68/praisonaiagents-0.1.27-py3-none-any.whl", hash = "sha256:0e7ccfa0bf4cf1aa6f58e9112bde026e61d36a75ec73e582d8deabd158d8c4de", size = 620263, upload-time = "2025-12-23T16:07:35.048Z" },
]
[[package]]