Compare commits

...
8 Commits
Author SHA1 Message Date
Mervin Praison dc5b10fba8 Merge pull request #611 from MervinPraison/develop
Update PraisonAI version to 2.2.30 across Dockerfiles and related files
2025-06-05 18:18:04 +01:00
MervinPraison f0172e8339 Update PraisonAI version to 2.2.30 across Dockerfiles and related files
- Incremented the version of PraisonAI from 2.2.29 to 2.2.30 in Dockerfiles (Dockerfile, Dockerfile.chat, Dockerfile.dev, Dockerfile.ui).
- Updated the version in the README.md and pyproject.toml files to reflect the new version.
- Adjusted the deploy.py script to install the updated version of PraisonAI.
- Ensured consistency across all relevant files for seamless integration.
2025-06-05 18:17:47 +01:00
Mervin Praison 5c498a12de Merge pull request #610 from MervinPraison/claude/issue-605-20250605_165941
fix: resolve Memory import error with litellm compatibility
2025-06-05 18:16:11 +01:00
Mervin Praison 88410881e1 Rename test_session_import.py to src/praisonai/tests/unit/test_session_import.py 2025-06-05 18:10:43 +01:00
Mervin Praison 791d59f96e Rename test_memory_import.py to src/praisonai/tests/unit/test_memory_import.py 2025-06-05 18:10:25 +01:00
Mervin Praison cdbe1303ad Rename test_comprehensive_import.py to src/praisonai/tests/unit/test_comprehensive_import.py 2025-06-05 18:10:10 +01:00
claude[bot]andMervinPraison b63f931bea feat: add Memory to main package exports and comprehensive tests
- Export Memory class from main praisonaiagents package
- Add Memory to __all__ list for proper package API
- Create comprehensive test suite to verify all import scenarios
- Tests original failing import from GitHub issue
- Tests direct Memory imports and instantiation

Co-authored-by: MervinPraison <[email protected]>
2025-06-05 17:02:47 +00:00
claude[bot]andMervinPraison ff25b96f91 fix: resolve Memory import error by implementing litellm compatibility
- Add LITELLM_AVAILABLE flag for proper dependency detection
- Implement litellm → openai fallback pattern for all embedding operations
- Update search_short_term, store_long_term, search_long_term embedding calls
- Update calculate_quality_metrics to use litellm → openai fallback
- Add graceful degradation when neither litellm nor openai is available
- Fixes ImportError: cannot import name 'Memory' from 'praisonaiagents.memory'

Co-authored-by: MervinPraison <[email protected]>
2025-06-05 17:02:03 +00:00
16 changed files with 335 additions and 65 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 \
flask \
"praisonai>=2.2.29" \
"praisonai>=2.2.30" \
"praisonai[api]" \
gunicorn \
markdown
+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.2.29" \
"praisonai>=2.2.30" \
"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.2.29" \
"praisonai>=2.2.30" \
"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.2.29" \
"praisonai>=2.2.30" \
"praisonai[ui]" \
"praisonai[crewai]"
+2 -2
View File
@@ -121,7 +121,7 @@ healthcheck:
## 📦 Package Versions
All Docker images use consistent, up-to-date versions:
- PraisonAI: `>=2.2.29`
- PraisonAI: `>=2.2.30`
- PraisonAI Agents: `>=0.0.92`
- Python: `3.11-slim`
@@ -218,7 +218,7 @@ docker-compose up -d
### Version Pinning
To use specific versions, update the Dockerfile:
```dockerfile
RUN pip install "praisonai==2.2.29" "praisonaiagents==0.0.92"
RUN pip install "praisonai==2.2.30" "praisonaiagents==0.0.92"
```
## 🌐 Production Deployment
@@ -12,6 +12,7 @@ from .knowledge.knowledge import Knowledge
from .knowledge.chunking import Chunking
from .mcp.mcp import MCP
from .session import Session
from .memory.memory import Memory
from .guardrails import GuardrailResult, LLMGuardrail
from .main import (
TaskOutput,
@@ -43,6 +44,7 @@ __all__ = [
'ReflectionOutput',
'AutoAgents',
'Session',
'Memory',
'display_interaction',
'display_self_reflection',
'display_instruction',
@@ -29,6 +29,12 @@ try:
except ImportError:
OPENAI_AVAILABLE = False
try:
import litellm
LITELLM_AVAILABLE = True
except ImportError:
LITELLM_AVAILABLE = False
@@ -340,14 +346,28 @@ class Memory:
elif self.use_rag and hasattr(self, "chroma_col"):
try:
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
input=query,
model="text-embedding-3-small"
)
query_embedding = response.data[0].embedding
if LITELLM_AVAILABLE:
# Use LiteLLM for consistency with the rest of the codebase
import litellm
response = litellm.embedding(
model="text-embedding-3-small",
input=query
)
query_embedding = response.data[0]["embedding"]
elif OPENAI_AVAILABLE:
# Fallback to OpenAI client
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
input=query,
model="text-embedding-3-small"
)
query_embedding = response.data[0].embedding
else:
self._log_verbose("Neither litellm nor openai available for embeddings", logging.WARNING)
return []
resp = self.chroma_col.query(
query_embeddings=[query_embedding],
@@ -464,19 +484,39 @@ class Memory:
# Store in vector database if enabled
if self.use_rag and hasattr(self, "chroma_col"):
try:
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) # Ensure API key is correctly set
logger.info("Getting embeddings from OpenAI...")
logger.debug(f"Embedding input text: {text}") # Log the input text
response = client.embeddings.create(
input=text,
model="text-embedding-3-small"
)
embedding = response.data[0].embedding
logger.info("Successfully got embeddings")
logger.debug(f"Received embedding of length: {len(embedding)}") # Log embedding details
if LITELLM_AVAILABLE:
# Use LiteLLM for consistency with the rest of the codebase
import litellm
logger.info("Getting embeddings from LiteLLM...")
logger.debug(f"Embedding input text: {text}")
response = litellm.embedding(
model="text-embedding-3-small",
input=text
)
embedding = response.data[0]["embedding"]
logger.info("Successfully got embeddings from LiteLLM")
logger.debug(f"Received embedding of length: {len(embedding)}")
elif OPENAI_AVAILABLE:
# Fallback to OpenAI client
from openai import OpenAI
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
logger.info("Getting embeddings from OpenAI...")
logger.debug(f"Embedding input text: {text}")
response = client.embeddings.create(
input=text,
model="text-embedding-3-small"
)
embedding = response.data[0].embedding
logger.info("Successfully got embeddings from OpenAI")
logger.debug(f"Received embedding of length: {len(embedding)}")
else:
logger.warning("Neither litellm nor openai available for embeddings")
return
# Sanitize metadata for ChromaDB
sanitized_metadata = self._sanitize_metadata(metadata)
@@ -527,15 +567,28 @@ class Memory:
elif self.use_rag and hasattr(self, "chroma_col"):
try:
from openai import OpenAI
client = OpenAI()
# Get query embedding
response = client.embeddings.create(
input=query,
model="text-embedding-3-small" # Using consistent model
)
query_embedding = response.data[0].embedding
if LITELLM_AVAILABLE:
# Use LiteLLM for consistency with the rest of the codebase
import litellm
response = litellm.embedding(
model="text-embedding-3-small",
input=query
)
query_embedding = response.data[0]["embedding"]
elif OPENAI_AVAILABLE:
# Fallback to OpenAI client
from openai import OpenAI
client = OpenAI()
response = client.embeddings.create(
input=query,
model="text-embedding-3-small"
)
query_embedding = response.data[0].embedding
else:
self._log_verbose("Neither litellm nor openai available for embeddings", logging.WARNING)
return []
# Search ChromaDB with embedding
resp = self.chroma_col.query(
@@ -910,21 +963,44 @@ class Memory:
"""
try:
# Use LiteLLM for consistency with the rest of the codebase
import litellm
# Convert model name if it's in litellm format
model_name = llm or "gpt-4o-mini"
response = litellm.completion(
model=model_name,
messages=[{
"role": "user",
"content": custom_prompt or default_prompt
}],
response_format={"type": "json_object"},
temperature=0.3
)
if LITELLM_AVAILABLE:
# Use LiteLLM for consistency with the rest of the codebase
import litellm
# Convert model name if it's in litellm format
model_name = llm or "gpt-4o-mini"
response = litellm.completion(
model=model_name,
messages=[{
"role": "user",
"content": custom_prompt or default_prompt
}],
response_format={"type": "json_object"},
temperature=0.3
)
elif OPENAI_AVAILABLE:
# Fallback to OpenAI client
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.create(
model=llm or "gpt-4o-mini",
messages=[{
"role": "user",
"content": custom_prompt or default_prompt
}],
response_format={"type": "json_object"},
temperature=0.3
)
else:
logger.error("Neither litellm nor openai available for quality calculation")
return {
"completeness": 0.0,
"relevance": 0.0,
"clarity": 0.0,
"accuracy": 0.0
}
metrics = json.loads(response.choices[0].message.content)
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.0.101"
version = "0.0.102"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
requires-python = ">=3.10"
authors = [
+1 -1
View File
@@ -2398,7 +2398,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.101"
version = "0.0.102"
source = { editable = "." }
dependencies = [
{ name = "mcp" },
+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.2.29.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.29.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.30.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v2.2.30.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
+1 -1
View File
@@ -56,7 +56,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.2.29 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==2.2.30 gunicorn markdown\n")
file.write("EXPOSE 8080\n")
file.write('CMD ["gunicorn", "-b", "0.0.0.0:8080", "api:app"]\n')
+4 -4
View File
@@ -1,6 +1,6 @@
[project]
name = "PraisonAI"
version = "2.2.29"
version = "2.2.30"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
readme = "README.md"
license = ""
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.0.101",
"praisonaiagents>=0.0.102",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
@@ -95,7 +95,7 @@ autogen = ["pyautogen>=0.2.19", "praisonai-tools>=0.0.15", "crewai"]
[tool.poetry]
name = "PraisonAI"
version = "2.2.29"
version = "2.2.30"
description = "PraisonAI is an AI Agents Framework with Self Reflection. PraisonAI application combines PraisonAI Agents, AutoGen, and CrewAI into a low-code solution for building and managing multi-agent LLM systems, focusing on simplicity, customisation, and efficient human-agent collaboration."
authors = ["Mervin Praison"]
license = ""
@@ -113,7 +113,7 @@ python = ">=3.10,<3.13"
rich = ">=13.7"
markdown = ">=3.5"
pyparsing = ">=3.0.0"
praisonaiagents = ">=0.0.101"
praisonaiagents = ">=0.0.102"
python-dotenv = ">=0.19.0"
instructor = ">=1.3.3"
PyYAML = ">=6.0"
@@ -0,0 +1,135 @@
#!/usr/bin/env python3
"""
Comprehensive test script to verify all import scenarios work correctly
Tests the original failing import from the GitHub issue
"""
import sys
import os
# Add the praisonai-agents source to Python path
sys.path.insert(0, '/home/runner/work/PraisonAI/PraisonAI/src/praisonai-agents')
def test_original_failing_import():
"""Test the exact import that was failing in the GitHub issue"""
print("=== Testing Original Failing Import ===")
try:
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
print('✅ SUCCESS: from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents')
return True
except ImportError as e:
print(f'❌ ERROR: {e}')
import traceback
traceback.print_exc()
return False
except Exception as e:
print(f'❌ UNEXPECTED ERROR: {e}')
import traceback
traceback.print_exc()
return False
def test_memory_direct_import():
"""Test direct Memory import"""
print("\n=== Testing Direct Memory Import ===")
try:
from praisonaiagents.memory import Memory
print('✅ SUCCESS: from praisonaiagents.memory import Memory')
return True
except ImportError as e:
print(f'❌ ERROR: {e}')
import traceback
traceback.print_exc()
return False
except Exception as e:
print(f'❌ UNEXPECTED ERROR: {e}')
import traceback
traceback.print_exc()
return False
def test_memory_from_package_root():
"""Test Memory import from package root"""
print("\n=== Testing Memory Import from Package Root ===")
try:
from praisonaiagents import Memory
print('✅ SUCCESS: from praisonaiagents import Memory')
return True
except ImportError as e:
print(f'❌ ERROR: {e}')
import traceback
traceback.print_exc()
return False
except Exception as e:
print(f'❌ UNEXPECTED ERROR: {e}')
import traceback
traceback.print_exc()
return False
def test_session_import():
"""Test Session import which depends on Memory"""
print("\n=== Testing Session Import ===")
try:
from praisonaiagents.session import Session
print('✅ SUCCESS: from praisonaiagents.session import Session')
return True
except ImportError as e:
print(f'❌ ERROR: {e}')
import traceback
traceback.print_exc()
return False
except Exception as e:
print(f'❌ UNEXPECTED ERROR: {e}')
import traceback
traceback.print_exc()
return False
def test_memory_instantiation():
"""Test that Memory can be instantiated without errors"""
print("\n=== Testing Memory Instantiation ===")
try:
from praisonaiagents.memory import Memory
# Test with minimal config (no external dependencies)
config = {"provider": "none"}
memory = Memory(config=config)
print('✅ SUCCESS: Memory instance created with provider="none"')
# Test basic methods don't fail immediately
memory.store_short_term("test content", metadata={"test": True})
results = memory.search_short_term("test", limit=1)
print('✅ SUCCESS: Basic memory operations work')
return True
except Exception as e:
print(f'❌ ERROR: {e}')
import traceback
traceback.print_exc()
return False
def run_all_tests():
"""Run all tests and report results"""
print("🔍 Running comprehensive import tests...")
tests = [
test_original_failing_import,
test_memory_direct_import,
test_memory_from_package_root,
test_session_import,
test_memory_instantiation
]
results = []
for test in tests:
results.append(test())
print(f"\n📊 Test Results: {sum(results)}/{len(results)} tests passed")
if all(results):
print("🎉 ALL TESTS PASSED! The Memory import issue has been resolved.")
else:
print("❌ Some tests failed. The issue may not be fully resolved.")
return all(results)
if __name__ == "__main__":
success = run_all_tests()
sys.exit(0 if success else 1)
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
"""
Test script to verify Memory import works correctly
"""
import sys
import os
# Add the praisonai-agents source to Python path
sys.path.insert(0, '/home/runner/work/PraisonAI/PraisonAI/src/praisonai-agents')
try:
from praisonaiagents.memory import Memory
print('SUCCESS: Memory import works correctly')
print('Memory class found:', Memory)
# Try to create a minimal instance to ensure it doesn't fail immediately
config = {"provider": "none"} # Use the simplest provider
memory = Memory(config=config)
print('SUCCESS: Memory instance created successfully')
except ImportError as e:
print('ERROR:', e)
import traceback
traceback.print_exc()
except Exception as e:
print('UNEXPECTED ERROR:', e)
import traceback
traceback.print_exc()
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
"""
Test script to verify session.py import works correctly (which imports Memory)
"""
import sys
import os
# Add the praisonai-agents source to Python path
sys.path.insert(0, '/home/runner/work/PraisonAI/PraisonAI/src/praisonai-agents')
try:
from praisonaiagents.session import Session
print('SUCCESS: Session import works correctly')
print('Session class found:', Session)
# This was the failing import chain
from praisonaiagents.agents.agents import Agent, Task, PraisonAIAgents
print('SUCCESS: Agent, Task, PraisonAIAgents import works correctly')
except ImportError as e:
print('ERROR:', e)
import traceback
traceback.print_exc()
except Exception as e:
print('UNEXPECTED ERROR:', e)
import traceback
traceback.print_exc()
+5 -5
View File
@@ -3931,7 +3931,7 @@ wheels = [
[[package]]
name = "praisonai"
version = "2.2.29"
version = "2.2.30"
source = { editable = "." }
dependencies = [
{ name = "instructor" },
@@ -4073,7 +4073,7 @@ requires-dist = [
{ name = "plotly", marker = "extra == 'realtime'", specifier = ">=5.24.0" },
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.0.15" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.0.15" },
{ name = "praisonaiagents", specifier = ">=0.0.101" },
{ name = "praisonaiagents", specifier = ">=0.0.102" },
{ name = "pyautogen", marker = "extra == 'autogen'", specifier = ">=0.2.19" },
{ name = "pydantic", marker = "extra == 'chat'", specifier = "<=2.10.1" },
{ name = "pydantic", marker = "extra == 'code'", specifier = "<=2.10.1" },
@@ -4130,7 +4130,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.0.101"
version = "0.0.102"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "mcp" },
@@ -4138,9 +4138,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6a/20/5b34f6a42752a0033034483ef116d419e5b0c51a5bcb92aa285312a62466/praisonaiagents-0.0.101.tar.gz", hash = "sha256:55d2a79726aac286a93815768a6cfa04c821f430370f276b18e5a2aab698aa2b", size = 145011 }
sdist = { url = "https://files.pythonhosted.org/packages/19/e5/6f89d32b022f86561a9ffd5ceba5e8bcd29a531396c19a591ac12efdbf3b/praisonaiagents-0.0.102.tar.gz", hash = "sha256:c51ef93663a4d46c09c956b34a291fbb2bfefc07f546add587c441f8d801113a", size = 145079 }
wheels = [
{ url = "https://files.pythonhosted.org/packages/89/57/3f17cc757f6c12125a6a6e3518d8221ba74bae10d5512362134db6dda8b5/praisonaiagents-0.0.101-py3-none-any.whl", hash = "sha256:4c6174b50e6084cf375b1eef196dfc4f48c72b82d1edf043660d48754558e14c", size = 164959 },
{ url = "https://files.pythonhosted.org/packages/0e/e4/2ddc2b3a38e118454ee6c047e08b2f0baea3fcf45fe85cffa19221e79968/praisonaiagents-0.0.102-py3-none-any.whl", hash = "sha256:52dfe9d15a0a0c6d44194e45d91fe513e5633164f3ff6426c41068c302c5ff7a", size = 165203 },
]
[[package]]