Compare commits

...
1 Commits
Author SHA1 Message Date
Mervin Praison 585b68d02c Release v3.6.2 2026-01-10 09:08:53 +00:00
18 changed files with 414 additions and 16 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>=3.6.1" \
"praisonai>=3.6.2" \
"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>=3.6.1" \
"praisonai>=3.6.2" \
"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>=3.6.1" \
"praisonai>=3.6.2" \
"praisonai[ui]" \
"praisonai[crewai]"
+16
View File
@@ -23,6 +23,7 @@ examples/
| Category | Examples | Docs |
|----------|----------|------|
| **Consolidated Params** | [consolidated_params/](consolidated_params/) | [📖](https://docs.praison.ai/api/consolidated-params) |
| **Agents** | [python/agents/](python/agents/) | [📖](https://docs.praison.ai/concepts/agents) |
| **Workflows** | [python/workflows/](python/workflows/) | [📖](https://docs.praison.ai/features/workflows) |
| **Model Router** | [python/agents/router-agent-cost-optimization.py](python/agents/router-agent-cost-optimization.py) | [📖](https://docs.praison.ai/features/model-router) |
@@ -35,6 +36,21 @@ examples/
| **Serve** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/serve) |
| **Endpoints** | [serve/](serve/) | [📖](https://docs.praison.ai/cli/endpoints) |
## Consolidated Params Examples
Agent-centric API with unified parameter resolution. Precedence: Instance > Config > Array > Dict > String > Bool > Default
| Example | Description |
|---------|-------------|
| [basic_agent.py](consolidated_params/basic_agent.py) | Minimal agent with memory |
| [basic_agents.py](consolidated_params/basic_agents.py) | Multi-agent with memory+planning |
| [basic_workflow.py](consolidated_params/basic_workflow.py) | Workflow with consolidated params |
| [basic_memory.py](consolidated_params/basic_memory.py) | Memory presets (file, redis, postgres) |
| [basic_guardrails.py](consolidated_params/basic_guardrails.py) | Guardrails with callable or config |
| [basic_workflow_agentlike.py](consolidated_params/basic_workflow_agentlike.py) | Workflow with agent-like params |
| [basic_step_override.py](consolidated_params/basic_step_override.py) | Step-level override of workflow defaults |
| [advanced_workflow_full_features.py](consolidated_params/advanced_workflow_full_features.py) | All consolidated params |
## Serve Examples
| Example | Description | CLI Command |
@@ -0,0 +1,55 @@
"""Advanced Workflow with all consolidated params configured."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
from praisonaiagents.workflows.workflow_configs import (
WorkflowOutputConfig, WorkflowPlanningConfig, WorkflowMemoryConfig,
)
# Full-featured workflow with all consolidated params
workflow = Workflow(
name="FullFeaturedWorkflow",
description="Demonstrates all agent-like consolidated params",
steps=[
WorkflowStep(
name="researcher",
action="Research: {{input}}",
agent=Agent(instructions="You are a researcher."),
knowledge=["research_docs/"], # Step-specific knowledge
web="duckduckgo", # Use DuckDuckGo for this step
),
WorkflowStep(
name="analyzer",
action="Analyze the research",
agent=Agent(instructions="You are an analyst."),
reflection="thorough", # Thorough reflection for analysis
guardrails="strict", # Strict validation
),
WorkflowStep(
name="writer",
action="Write the final report",
agent=Agent(instructions="You are a writer."),
autonomy=True, # Enable autonomy for writing
),
],
# Workflow-level consolidated params
output=WorkflowOutputConfig(verbose=True, stream=True),
planning=WorkflowPlanningConfig(enabled=True, reasoning=True),
memory=WorkflowMemoryConfig(backend="file"),
# Agent-like params
autonomy=True,
knowledge=["shared_docs/"],
guardrails=True,
web=True,
reflection=True,
)
if __name__ == "__main__":
print(f"Workflow: {workflow.name}")
print(f"Output verbose: {workflow._verbose}")
print(f"Planning enabled: {workflow._planning_enabled}")
print(f"Memory config: {workflow._memory_config}")
print(f"Autonomy: {workflow.autonomy}")
print(f"Knowledge: {workflow.knowledge}")
print(f"Guardrails: {workflow.guardrails}")
print(f"Web: {workflow.web}")
print(f"Reflection: {workflow.reflection}")
@@ -0,0 +1,33 @@
"""Basic example showing step-level override of workflow defaults."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Workflow with defaults
workflow = Workflow(
name="StepOverrideWorkflow",
steps=[
WorkflowStep(
name="step1",
action="Process with workflow defaults",
agent=Agent(instructions="You are a processor."),
# Uses workflow-level web=True (inherited)
),
WorkflowStep(
name="step2",
action="Process with step override",
agent=Agent(instructions="You are a processor."),
# Override workflow default
web=False, # Disable web for this step
reflection="thorough", # Use thorough reflection preset
),
],
# Workflow defaults
web=True,
reflection=True,
)
if __name__ == "__main__":
print(f"Workflow web default: {workflow.web}")
print(f"Step1 web: {workflow.steps[0].web}") # None (uses workflow default)
print(f"Step2 web: {workflow.steps[1].web}") # False (overridden)
print(f"Step2 reflection: {workflow.steps[1].reflection}") # thorough
@@ -0,0 +1,32 @@
"""Basic Workflow with Agent-like consolidated params."""
from praisonaiagents import Agent
from praisonaiagents.workflows import Workflow, WorkflowStep
# Workflow with agent-like params (knowledge, web, guardrails, reflection)
workflow = Workflow(
name="AgentLikeWorkflow",
steps=[
WorkflowStep(
name="researcher",
action="Research the topic: {{input}}",
agent=Agent(instructions="You are a researcher."),
),
WorkflowStep(
name="writer",
action="Write about the research findings",
agent=Agent(instructions="You are a writer."),
),
],
# Agent-like consolidated params
knowledge=["docs/"], # Enable RAG
web=True, # Enable web search
guardrails=True, # Enable guardrails
reflection=True, # Enable self-reflection
)
if __name__ == "__main__":
print(f"Workflow: {workflow.name}")
print(f"Knowledge: {workflow.knowledge}")
print(f"Web: {workflow.web}")
print(f"Guardrails: {workflow.guardrails}")
print(f"Reflection: {workflow.reflection}")
@@ -243,12 +243,17 @@ class WorkflowStep:
# ============================================================
# CONSOLIDATED FEATURE PARAMS (workflow-centric API)
# Precedence: Instance > Config > String > Bool > Default
# Precedence: Instance > Config > Array > Dict > String > Bool > Default
# ============================================================
context: Optional[Any] = None # Union[bool, List[str], WorkflowStepContextConfig] - context handling
output: Optional[Any] = None # Union[str, WorkflowStepOutputConfig] - output handling
execution: Optional[Any] = None # Union[str, WorkflowStepExecutionConfig] - execution control
routing: Optional[Any] = None # Union[List[str], WorkflowStepRoutingConfig] - branching
# NEW: Agent-like consolidated params for feature parity
autonomy: Optional[Any] = None # Union[bool, AutonomyConfig] - agent autonomy
knowledge: Optional[Any] = None # Union[bool, List[str], KnowledgeConfig] - RAG
web: Optional[Any] = None # Union[bool, WebConfig] - web search/fetch
reflection: Optional[Any] = None # Union[bool, ReflectionConfig] - self-reflection
# Status tracking
status: str = "pending" # pending, running, completed, failed, skipped
@@ -268,6 +273,11 @@ class WorkflowStep:
_on_error: str = field(default="stop", repr=False)
_next_steps: Optional[List[str]] = field(default=None, repr=False)
_branch_condition: Optional[Dict[str, List[str]]] = field(default=None, repr=False)
# NEW: Resolved configs for agent-like params
_autonomy_config: Optional[Any] = field(default=None, repr=False)
_knowledge_config: Optional[Any] = field(default=None, repr=False)
_web_config: Optional[Any] = field(default=None, repr=False)
_reflection_config: Optional[Any] = field(default=None, repr=False)
def __post_init__(self):
"""Resolve consolidated params to internal values."""
@@ -316,6 +326,50 @@ class WorkflowStep:
if route_cfg:
self._next_steps = route_cfg.next_steps
self._branch_condition = route_cfg.branches
# Resolve NEW agent-like params using canonical resolver
from ..config.param_resolver import resolve, ArrayMode
from ..config.presets import (
WEB_PRESETS, REFLECTION_PRESETS, AUTONOMY_PRESETS, KNOWLEDGE_PRESETS,
)
try:
from ..config.feature_configs import (
AutonomyConfig, KnowledgeConfig, WebConfig, ReflectionConfig,
)
except ImportError:
AutonomyConfig = KnowledgeConfig = WebConfig = ReflectionConfig = None
# Resolve autonomy
if AutonomyConfig and self.autonomy is not None:
self._autonomy_config = resolve(
value=self.autonomy, param_name="autonomy",
config_class=AutonomyConfig, presets=AUTONOMY_PRESETS,
default=None,
)
# Resolve knowledge
if KnowledgeConfig and self.knowledge is not None:
self._knowledge_config = resolve(
value=self.knowledge, param_name="knowledge",
config_class=KnowledgeConfig, presets=KNOWLEDGE_PRESETS,
array_mode=ArrayMode.SOURCES, default=None,
)
# Resolve web
if WebConfig and self.web is not None:
self._web_config = resolve(
value=self.web, param_name="web",
config_class=WebConfig, presets=WEB_PRESETS,
default=None,
)
# Resolve reflection
if ReflectionConfig and self.reflection is not None:
self._reflection_config = resolve(
value=self.reflection, param_name="reflection",
config_class=ReflectionConfig, presets=REFLECTION_PRESETS,
default=None,
)
# Property accessors for backward compatibility
@property
@@ -439,13 +493,20 @@ class Workflow:
# ============================================================
# CONSOLIDATED FEATURE PARAMS (workflow-centric API)
# Precedence: Instance > Config > String > Bool > Default
# Precedence: Instance > Config > Array > Dict > String > Bool > Default
# Workflow is "Agents in an organised way" - supports same params as Agents
# ============================================================
output: Optional[Any] = None # Union[str, WorkflowOutputConfig] - verbose/stream
planning: Optional[Any] = False # Union[bool, str, WorkflowPlanningConfig] - planning mode
memory: Optional[Any] = None # Union[bool, WorkflowMemoryConfig, instance] - memory
hooks: Optional[Any] = None # WorkflowHooksConfig - lifecycle callbacks
context: Optional[Any] = False # Union[bool, ManagerConfig, ContextManager] - context management
# NEW: Agent-like consolidated params for feature parity
autonomy: Optional[Any] = None # Union[bool, AutonomyConfig] - agent autonomy
knowledge: Optional[Any] = None # Union[bool, List[str], KnowledgeConfig] - RAG
guardrails: Optional[Any] = None # Union[bool, Callable, GuardrailConfig] - validation
web: Optional[Any] = None # Union[bool, WebConfig] - web search/fetch
reflection: Optional[Any] = None # Union[bool, ReflectionConfig] - self-reflection
# Status tracking
status: str = "not_started" # not_started, running, completed, failed
@@ -461,6 +522,12 @@ class Workflow:
_hooks_config: Optional[Any] = field(default=None, repr=False)
_context_manager: Optional[Any] = field(default=None, repr=False)
_context_manager_initialized: bool = field(default=False, repr=False)
# NEW: Resolved configs for agent-like params (for propagation to steps/agents)
_autonomy_config: Optional[Any] = field(default=None, repr=False)
_knowledge_config: Optional[Any] = field(default=None, repr=False)
_guardrails_config: Optional[Any] = field(default=None, repr=False)
_web_config: Optional[Any] = field(default=None, repr=False)
_reflection_config: Optional[Any] = field(default=None, repr=False)
def __post_init__(self):
"""Resolve consolidated params to internal values."""
@@ -490,6 +557,62 @@ class Workflow:
# Resolve hooks param
self._hooks_config = resolve_hooks_config(self.hooks)
# Resolve NEW agent-like params using canonical resolver
# These are stored for propagation to steps/agents
from ..config.param_resolver import resolve, ArrayMode
from ..config.presets import (
WEB_PRESETS, REFLECTION_PRESETS, GUARDRAIL_PRESETS,
AUTONOMY_PRESETS, KNOWLEDGE_PRESETS,
)
try:
from ..config.feature_configs import (
AutonomyConfig, KnowledgeConfig, GuardrailConfig,
WebConfig, ReflectionConfig,
)
except ImportError:
AutonomyConfig = KnowledgeConfig = GuardrailConfig = None
WebConfig = ReflectionConfig = None
# Resolve autonomy
if AutonomyConfig and self.autonomy is not None:
self._autonomy_config = resolve(
value=self.autonomy, param_name="autonomy",
config_class=AutonomyConfig, presets=AUTONOMY_PRESETS,
default=None,
)
# Resolve knowledge
if KnowledgeConfig and self.knowledge is not None:
self._knowledge_config = resolve(
value=self.knowledge, param_name="knowledge",
config_class=KnowledgeConfig, presets=KNOWLEDGE_PRESETS,
array_mode=ArrayMode.SOURCES, default=None,
)
# Resolve guardrails
if GuardrailConfig and self.guardrails is not None:
self._guardrails_config = resolve(
value=self.guardrails, param_name="guardrails",
config_class=GuardrailConfig, presets=GUARDRAIL_PRESETS,
default=None,
)
# Resolve web
if WebConfig and self.web is not None:
self._web_config = resolve(
value=self.web, param_name="web",
config_class=WebConfig, presets=WEB_PRESETS,
default=None,
)
# Resolve reflection
if ReflectionConfig and self.reflection is not None:
self._reflection_config = resolve(
value=self.reflection, param_name="reflection",
config_class=ReflectionConfig, presets=REFLECTION_PRESETS,
default=None,
)
def to_dict(self) -> Dict[str, Any]:
return {
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
[project]
name = "praisonaiagents"
version = "0.10.9"
version = "0.10.10"
description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
readme = "README.md"
requires-python = ">=3.10"
@@ -620,5 +620,101 @@ class TestStrictDictValidation:
assert "unknown_field" in error_msg.lower() or "unknown" in error_msg.lower()
# =============================================================================
# PHASE 1 TDD: Tests for Workflow/WorkflowStep New Params (ALL GREEN target)
# =============================================================================
class TestWorkflowNewParams:
"""Test Workflow supports all consolidated params like Agents."""
def test_workflow_has_autonomy_param(self):
"""Workflow should have autonomy param."""
from praisonaiagents.workflows.workflows import Workflow
# Should accept autonomy param without error
workflow = Workflow(steps=[], autonomy=True)
assert hasattr(workflow, 'autonomy') or hasattr(workflow, '_autonomy_config')
def test_workflow_has_knowledge_param(self):
"""Workflow should have knowledge param."""
from praisonaiagents.workflows.workflows import Workflow
workflow = Workflow(steps=[], knowledge=["docs/"])
assert hasattr(workflow, 'knowledge') or hasattr(workflow, '_knowledge_config')
def test_workflow_has_guardrails_param(self):
"""Workflow should have guardrails param."""
from praisonaiagents.workflows.workflows import Workflow
workflow = Workflow(steps=[], guardrails=True)
assert hasattr(workflow, 'guardrails') or hasattr(workflow, '_guardrails_config')
def test_workflow_has_web_param(self):
"""Workflow should have web param."""
from praisonaiagents.workflows.workflows import Workflow
workflow = Workflow(steps=[], web=True)
assert hasattr(workflow, 'web') or hasattr(workflow, '_web_config')
def test_workflow_has_reflection_param(self):
"""Workflow should have reflection param."""
from praisonaiagents.workflows.workflows import Workflow
workflow = Workflow(steps=[], reflection=True)
assert hasattr(workflow, 'reflection') or hasattr(workflow, '_reflection_config')
class TestWorkflowStepNewParams:
"""Test WorkflowStep supports all consolidated params."""
def test_workflowstep_has_autonomy_param(self):
"""WorkflowStep should have autonomy param."""
from praisonaiagents.workflows.workflows import WorkflowStep
step = WorkflowStep(name="test", autonomy=True)
assert hasattr(step, 'autonomy') or hasattr(step, '_autonomy_config')
def test_workflowstep_has_knowledge_param(self):
"""WorkflowStep should have knowledge param."""
from praisonaiagents.workflows.workflows import WorkflowStep
step = WorkflowStep(name="test", knowledge=["docs/"])
assert hasattr(step, 'knowledge') or hasattr(step, '_knowledge_config')
def test_workflowstep_has_web_param(self):
"""WorkflowStep should have web param."""
from praisonaiagents.workflows.workflows import WorkflowStep
step = WorkflowStep(name="test", web=True)
assert hasattr(step, 'web') or hasattr(step, '_web_config')
def test_workflowstep_has_reflection_param(self):
"""WorkflowStep should have reflection param."""
from praisonaiagents.workflows.workflows import WorkflowStep
step = WorkflowStep(name="test", reflection=True)
assert hasattr(step, 'reflection') or hasattr(step, '_reflection_config')
class TestWorkflowPropagation:
"""Test workflow defaults propagate to steps/agents."""
def test_workflow_defaults_available_for_steps(self):
"""Workflow-level configs should be accessible for step propagation."""
from praisonaiagents.workflows.workflows import Workflow
workflow = Workflow(
steps=[],
knowledge=["docs/"],
web=True,
guardrails=True,
)
# Workflow should store resolved configs for propagation
assert workflow.knowledge is not None or hasattr(workflow, '_knowledge_config')
assert workflow.web is not None or hasattr(workflow, '_web_config')
assert workflow.guardrails is not None or hasattr(workflow, '_guardrails_config')
if __name__ == "__main__":
pytest.main([__file__, "-v"])
+1 -1
View File
@@ -2422,7 +2422,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.10.9"
version = "0.10.10"
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/v3.6.1.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.6.1.tar.gz | shasum -a 256`.split.first
url "https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.6.2.tar.gz"
sha256 `curl -sL https://github.com/MervinPraison/PraisonAI/archive/refs/tags/v3.6.2.tar.gz | shasum -a 256`.split.first
license "MIT"
depends_on "[email protected]"
@@ -68,6 +68,31 @@ def chat_main(
no_acp: bool = typer.Option(False, "--no-acp", help="Disable ACP tools"),
no_lsp: bool = typer.Option(False, "--no-lsp", help="Disable LSP tools"),
autonomy: bool = typer.Option(True, "--autonomy/--no-autonomy", help="Enable agent autonomy for complex tasks"),
# NEW: Agent-like consolidated params for ALL GREEN consistency
knowledge: Optional[str] = typer.Option(
None, "--knowledge", "-k",
help="Enable knowledge/RAG. Use --knowledge for default, --knowledge=docs/ for sources",
is_flag=False,
flag_value="true",
),
guardrails: Optional[str] = typer.Option(
None, "--guardrails",
help="Enable guardrails. Use --guardrails for default, --guardrails=strict for preset",
is_flag=False,
flag_value="true",
),
web: Optional[str] = typer.Option(
None, "--web",
help="Enable web search. Use --web for default, --web=duckduckgo for preset",
is_flag=False,
flag_value="true",
),
reflection: Optional[str] = typer.Option(
None, "--reflection",
help="Enable self-reflection. Use --reflection for default, --reflection=thorough for preset",
is_flag=False,
flag_value="true",
),
profile: bool = typer.Option(False, "--profile", help="Enable CLI profiling (timing breakdown)"),
profile_deep: bool = typer.Option(False, "--profile-deep", help="Enable deep profiling (cProfile stats, higher overhead)"),
):
+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==3.6.1 gunicorn markdown\n")
file.write("RUN pip install flask praisonai==3.6.2 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__ = "3.6.1"
__version__ = "3.6.2"
+1 -1
View File
@@ -12,7 +12,7 @@ dependencies = [
"rich>=13.7",
"markdown>=3.5",
"pyparsing>=3.0.0",
"praisonaiagents>=0.10.9",
"praisonaiagents>=0.10.10",
"python-dotenv>=0.19.0",
"instructor>=1.3.3",
"PyYAML>=6.0",
+18
View File
@@ -130,6 +130,19 @@ def bump_version(new_version: str, agents_version: Optional[str] = None):
print("\n✨ Version bump complete!")
def validate_dependencies() -> bool:
"""Validate that uv lock will succeed before making any changes."""
praisonai_dir = get_praisonai_dir()
print("\n🔍 Validating dependencies (dry-run)...")
result = run(["uv", "lock", "--dry-run"], cwd=praisonai_dir, check=False)
if result.returncode != 0:
print("\n❌ Dependency validation failed. Fix the issues above before releasing.")
return False
print(" ✅ Dependencies validated successfully")
return True
def release(version: str):
"""Run the release process."""
root = get_project_root()
@@ -215,6 +228,11 @@ def main():
# Run bump version
bump_version(args.version, args.agents)
# Validate dependencies after version bump (before git operations)
if not validate_dependencies():
print("\n💡 Tip: Revert changes with 'git checkout .' if needed")
sys.exit(1)
# Run release
release(args.version)
+4 -4
View File
@@ -4276,7 +4276,7 @@ requires-dist = [
{ name = "praisonai-tools", marker = "extra == 'autogen'", specifier = ">=0.1.0" },
{ name = "praisonai-tools", marker = "extra == 'autogen-v4'", specifier = ">=0.1.0" },
{ name = "praisonai-tools", marker = "extra == 'crewai'", specifier = ">=0.1.0" },
{ name = "praisonaiagents", specifier = ">=0.10.9" },
{ name = "praisonaiagents", specifier = ">=0.10.10" },
{ 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" },
@@ -4324,7 +4324,7 @@ wheels = [
[[package]]
name = "praisonaiagents"
version = "0.10.9"
version = "0.10.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "aiohttp" },
@@ -4333,9 +4333,9 @@ dependencies = [
{ name = "pydantic" },
{ name = "rich" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b9/8a/d7cd16c63778cdebb423973c25dfdc15fb6343f8e9108d775e87a3f3e40c/praisonaiagents-0.10.9.tar.gz", hash = "sha256:abcd5181433a83f65a7eae0524f25f4261d13f7344dcd793daf4fd9d0ff05dd0", size = 961802, upload-time = "2026-01-09T17:11:21.356Z" }
sdist = { url = "https://files.pythonhosted.org/packages/56/4f/d01c588827a74ddc58a8bf30cb7eb97671d210b7f5ef46f9eb2a7249f919/praisonaiagents-0.10.10.tar.gz", hash = "sha256:b6cfea93fef40b898575d0c1574134fdc9ec49754d2287e9ade90ba4381ca3d7", size = 962453, upload-time = "2026-01-10T08:57:35.82Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/23/7b/e228328cb10e61a5a605b91c674074249ac7d47f504fbd3dad34f98220dd/praisonaiagents-0.10.9-py3-none-any.whl", hash = "sha256:f85dd021f7321cd47bcc44062452febeeb4030790015ed03b0ff9351ee704cc4", size = 941067, upload-time = "2026-01-09T17:11:18.337Z" },
{ url = "https://files.pythonhosted.org/packages/07/fe/edd179c792d7f6143d3278c01daf37015fe4a2d98c5dc326fb309b263336/praisonaiagents-0.10.10-py3-none-any.whl", hash = "sha256:fa9bc6db1fb12ae25ea491db8e30eb98ac16c1e9798952cf617594c09999b826", size = 941797, upload-time = "2026-01-10T08:57:34.07Z" },
]
[[package]]