Compare commits

...
1 Commits
Author SHA1 Message Date
Mervin Praison d65840e092 Release v2.3.76 2025-12-23 05:40:52 +00:00
13 changed files with 125 additions and 43 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.75" \
"praisonai>=2.3.76" \
"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.75" \
"praisonai>=2.3.76" \
"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.75" \
"praisonai>=2.3.76" \
"praisonai[ui]" \
"praisonai[crewai]"
@@ -11,7 +11,7 @@ import sys
warnings.filterwarnings("ignore", message=".*There is no current event loop.*", category=DeprecationWarning)
warnings.filterwarnings("ignore", message=".*Pydantic serializer warnings.*")
warnings.filterwarnings("ignore", message=".*PydanticSerializationUnexpectedValue.*")
warnings.filterwarnings("ignore", message=".*Expected 9 fields but got.*")
warnings.filterwarnings("ignore", message=".*Expected \\d+ fields but got.*")
warnings.filterwarnings("ignore", message=".*Expected `StreamingChoices` but got.*")
warnings.filterwarnings("ignore", message=".*serialized value may not be as expected.*")
warnings.filterwarnings("ignore", message=".*Use 'content=<...>' to upload raw bytes/text content.*")
@@ -28,7 +28,7 @@ SUPPRESSED_PATTERNS = [
"The `dict` method is deprecated; use `model_dump` instead",
"Pydantic serializer warnings",
"PydanticSerializationUnexpectedValue",
"Expected 9 fields but got 5 for type `Message`",
"Expected", # Catches all "Expected N fields but got M" patterns
"Expected `StreamingChoices` but got `Choices`",
"serialized value may not be as expected",
"Mixing V1 models and V2 models",
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.1.23"
version = "0.1.24"
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.23"
version = "0.1.24"
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.75.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.75.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.76.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.3.76.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
@@ -45,8 +45,10 @@ class AutoMemoryHandler(FlagHandler):
def _get_auto_memory(self, user_id: str = None):
"""Get AutoMemory instance lazily."""
try:
from praisonaiagents.memory import AutoMemory
return AutoMemory(user_id=user_id or "default")
from praisonaiagents.memory import AutoMemory, FileMemory
# AutoMemory requires a FileMemory instance
memory = FileMemory(user_id=user_id or "default")
return AutoMemory(memory=memory)
except ImportError:
self.print_status(
"AutoMemory requires praisonaiagents. Install with: pip install praisonaiagents",
@@ -71,33 +73,36 @@ class AutoMemoryHandler(FlagHandler):
config['auto_memory_user_id'] = flag_value.get('user_id', 'default')
return config
def extract_memories(self, text: str, user_id: str = None) -> Dict[str, Any]:
def extract_memories(self, text: str, user_id: str = None, user_message: str = None) -> list:
"""
Extract memories from text.
Extract and store memories from text.
Args:
text: Text to extract memories from
text: Assistant response text to extract memories from
user_id: User ID for memory isolation
user_message: Original user message (for context)
Returns:
Dictionary of extracted memories
List of extracted memories
"""
auto_memory = self._get_auto_memory(user_id)
if not auto_memory:
return {}
return []
try:
if hasattr(auto_memory, 'extract'):
memories = auto_memory.extract(text)
self.print_status(f"🧠 Extracted {len(memories)} memories", "success")
return memories
elif hasattr(auto_memory, 'process'):
result = auto_memory.process(text)
return result
# Use process_interaction which extracts AND stores memories
memories = auto_memory.process_interaction(
user_message=user_message or text,
assistant_response=text if user_message else None,
store=True # Store the memories
)
if memories:
self.print_status(f"🧠 Extracted and stored {len(memories)} memories", "success")
return memories
except Exception as e:
self.log(f"Memory extraction failed: {e}", "error")
return {}
return []
def store_memory(self, content: str, user_id: str = None, importance: float = 0.5) -> bool:
"""
@@ -127,13 +132,14 @@ class AutoMemoryHandler(FlagHandler):
self.log(f"Memory storage failed: {e}", "error")
return False
def post_process_result(self, result: Any, flag_value: Any) -> Any:
def post_process_result(self, result: Any, flag_value: Any, user_message: str = None) -> Any:
"""
Post-process result to extract and store memories.
Args:
result: Agent output
flag_value: Boolean or dict with configuration
user_message: Original user message for context
Returns:
Original result (memories are stored)
@@ -144,15 +150,18 @@ class AutoMemoryHandler(FlagHandler):
user_id = None
if isinstance(flag_value, dict):
user_id = flag_value.get('user_id')
user_message = flag_value.get('user_message', user_message)
# Extract memories from result
# Extract and store memories from result
text = str(result)
memories = self.extract_memories(text, user_id)
memories = self.extract_memories(text, user_id, user_message=user_message)
if memories:
self.print_status("\n🧠 Auto-extracted Memories:", "info")
for key, value in memories.items():
self.print_status(f" • {key}: {value[:50]}...", "info")
for mem in memories:
mem_type = mem.get('type', 'unknown')
content = mem.get('content', str(mem))[:50]
self.print_status(f" • {mem_type}: {content}...", "info")
return result
+80 -7
View File
@@ -5,6 +5,42 @@ import argparse
import warnings
import os
# Suppress Pydantic serialization warnings from LiteLLM BEFORE any imports
# These warnings occur when LiteLLM's response objects have field mismatches
# Using both filterwarnings AND patching warnings.warn for complete suppression
warnings.filterwarnings("ignore", message=".*Pydantic serializer warnings.*")
warnings.filterwarnings("ignore", message=".*PydanticSerializationUnexpectedValue.*")
warnings.filterwarnings("ignore", message=".*Expected \\d+ fields but got.*")
warnings.filterwarnings("ignore", message=".*Expected `StreamingChoices`.*")
warnings.filterwarnings("ignore", message=".*Expected `Message`.*")
warnings.filterwarnings("ignore", message=".*serialized value may not be as expected.*")
warnings.filterwarnings("ignore", category=UserWarning, module="pydantic.*")
# Patch warnings.showwarning to intercept ALL warnings including those from crewai's patched warn
# This is the final output function that actually displays warnings
_SUPPRESSED_PATTERNS = [
"Pydantic serializer warnings",
"PydanticSerializationUnexpectedValue",
"Expected", # Catches "Expected N fields but got M"
"StreamingChoices",
"serialized value may not be as expected",
"duckduckgo_search", # Suppress duckduckgo rename warning
]
_original_showwarning = warnings.showwarning
def _patched_showwarning(message, category, filename, lineno, file=None, line=None):
msg_str = str(message)
for pattern in _SUPPRESSED_PATTERNS:
if pattern in msg_str:
return
if category is UserWarning and "pydantic" in filename.lower():
return
_original_showwarning(message, category, filename, lineno, file, line)
warnings.showwarning = _patched_showwarning
# Suppress crewai RuntimeWarning about module loading order (only in non-debug mode)
# This warning is harmless and occurs when running as `python -m praisonai.cli.main`
if os.environ.get('LOGLEVEL', 'INFO').upper() != 'DEBUG':
@@ -1342,12 +1378,47 @@ class PraisonAI:
console.print(table)
# Show recent memories
# Show recent short-term memories
print("\n[bold]Recent Short-term Memories:[/bold]")
short_term = memory.get_short_term(limit=5)
for i, item in enumerate(short_term, 1):
content = item.get('content', str(item))[:100]
print(f" {i}. {content}")
if short_term:
for i, item in enumerate(short_term, 1):
content = item.get('content', str(item))[:100]
print(f" {i}. {content}")
else:
print(" [dim]No short-term memories[/dim]")
# Show long-term memories
print("\n[bold]Long-term Memories:[/bold]")
long_term = memory.get_long_term(limit=10)
if long_term:
for i, item in enumerate(long_term, 1):
# Handle both dict and MemoryItem objects
if hasattr(item, 'content'):
content = str(item.content)[:100]
importance = getattr(item, 'importance', 0)
else:
content = item.get('content', str(item))[:100]
importance = item.get('importance', 0)
print(f" {i}. [{importance:.1f}] {content}")
else:
print(" [dim]No long-term memories[/dim]")
# Show entities
print("\n[bold]Entities:[/bold]")
entities = memory.get_all_entities()
if entities:
for entity in entities[:10]:
# Handle both dict and Entity objects
if hasattr(entity, 'name'):
name = entity.name
entity_type = getattr(entity, 'entity_type', 'unknown')
else:
name = entity.get('name', 'Unknown')
entity_type = entity.get('entity_type', 'unknown')
print(f" • {name} ({entity_type})")
else:
print(" [dim]No entities[/dim]")
elif action == 'add':
if not action_args:
@@ -3118,9 +3189,8 @@ Provide ONLY the commit message, no explanations."""
telemetry = TelemetryHandler(verbose=getattr(self.args, 'verbose', False))
telemetry.enable()
# Auto Memory - Automatic memory extraction
# Auto Memory - Automatic memory extraction (handled post-processing, not as Agent param)
if getattr(self.args, 'auto_memory', False):
agent_config["auto_memory"] = True
print("[bold cyan]Auto Memory enabled - will extract and store memories[/bold cyan]")
# MCP - Model Context Protocol tools
@@ -3266,7 +3336,10 @@ Provide ONLY the commit message, no explanations."""
if hasattr(self, 'args') and getattr(self.args, 'auto_memory', False):
from .features.auto_memory import AutoMemoryHandler
auto_mem = AutoMemoryHandler(verbose=getattr(self.args, 'verbose', False))
auto_mem.post_process_result(result, {'user_id': getattr(self.args, 'user_id', None)})
auto_mem.post_process_result(
result,
{'user_id': getattr(self.args, 'user_id', None), 'user_message': prompt}
)
# Todo - Generate todo list from response
if hasattr(self, 'args') and getattr(self.args, 'todo', False):
+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.75 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.3.76 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.75"
__version__ = "2.3.76"
+1 -1
View File
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.1.23",
"praisonaiagents>=0.1.24",
"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.23" },
{ name = "praisonaiagents", specifier = ">=0.1.24" },
{ 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.23"
version = "0.1.24"
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/79/5e/563a931f0d79f6c64fa8f891ad6eb88cacbbd3f26af5efe52c07a31f11b4/praisonaiagents-0.1.23.tar.gz", hash = "sha256:7a840172892c67feb68e04167db827017d5df8a0e496eb91e309d0e272db60c9", size = 678076, upload-time = "2025-12-22T17:00:28.27Z" }
sdist = { url = "https://files.pythonhosted.org/packages/31/3e/9dec08dd8107b963cdb3ea3a77b5530e7f68b239c38c80f713be27920f1b/praisonaiagents-0.1.24.tar.gz", hash = "sha256:8a6d17c2df22f2171df11b44b44b817e72a6f34f1f5b4e389691bedbbff06621", size = 678110, upload-time = "2025-12-23T05:39:18.104Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/b4/b3/bf02847078595ab1cf109dfd3c7282eaece21f7b879fe96a3ae0d23e8571/praisonaiagents-0.1.23-py3-none-any.whl", hash = "sha256:a455c8fd04fdbd7dd7bf9755c24f19c9c496c404ef60a4fdfc4d4a51decb2e60", size = 616785, upload-time = "2025-12-22T17:00:26.55Z" },
{ url = "https://files.pythonhosted.org/packages/37/33/3b45e341433a01408f59ced6eb39da3ecb17067f0ff3c954fa38e07aaffb/praisonaiagents-0.1.24-py3-none-any.whl", hash = "sha256:03a1c476bb5287ad9e519b85a17a93c42ce11b01db87009fcde17a1901e4828a", size = 616792, upload-time = "2025-12-23T05:39:16.12Z" },
]
[[package]]