praisonaiagents 0.0.77__py3-none-any.whl → 0.0.79__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.
- praisonaiagents/agent/agent.py +187 -1
- {praisonaiagents-0.0.77.dist-info → praisonaiagents-0.0.79.dist-info}/METADATA +5 -1
- {praisonaiagents-0.0.77.dist-info → praisonaiagents-0.0.79.dist-info}/RECORD +5 -5
- {praisonaiagents-0.0.77.dist-info → praisonaiagents-0.0.79.dist-info}/WHEEL +0 -0
- {praisonaiagents-0.0.77.dist-info → praisonaiagents-0.0.79.dist-info}/top_level.txt +0 -0
praisonaiagents/agent/agent.py
CHANGED
@@ -22,6 +22,13 @@ import inspect
|
|
22
22
|
import uuid
|
23
23
|
from dataclasses import dataclass
|
24
24
|
|
25
|
+
# Global variables for API server
|
26
|
+
_server_started = False
|
27
|
+
_registered_agents = {}
|
28
|
+
_shared_app = None
|
29
|
+
|
30
|
+
# Don't import FastAPI dependencies here - use lazy loading instead
|
31
|
+
|
25
32
|
if TYPE_CHECKING:
|
26
33
|
from ..task.task import Task
|
27
34
|
|
@@ -1399,4 +1406,183 @@ Your Goal: {self.goal}
|
|
1399
1406
|
|
1400
1407
|
except Exception as e:
|
1401
1408
|
logging.error(f"Error in execute_tool_async: {str(e)}", exc_info=True)
|
1402
|
-
return {"error": f"Error in execute_tool_async: {str(e)}"}
|
1409
|
+
return {"error": f"Error in execute_tool_async: {str(e)}"}
|
1410
|
+
|
1411
|
+
def launch(self, path: str = '/', port: int = 8000, host: str = '0.0.0.0', debug: bool = False):
|
1412
|
+
"""
|
1413
|
+
Launch the agent as an HTTP API endpoint.
|
1414
|
+
|
1415
|
+
Args:
|
1416
|
+
path: API endpoint path (default: '/')
|
1417
|
+
port: Server port (default: 8000)
|
1418
|
+
host: Server host (default: '0.0.0.0')
|
1419
|
+
debug: Enable debug mode for uvicorn (default: False)
|
1420
|
+
|
1421
|
+
Returns:
|
1422
|
+
None
|
1423
|
+
"""
|
1424
|
+
global _server_started, _registered_agents, _shared_app
|
1425
|
+
|
1426
|
+
# Try to import FastAPI dependencies - lazy loading
|
1427
|
+
try:
|
1428
|
+
import uvicorn
|
1429
|
+
from fastapi import FastAPI, HTTPException, Request
|
1430
|
+
from fastapi.responses import JSONResponse
|
1431
|
+
from pydantic import BaseModel
|
1432
|
+
import threading
|
1433
|
+
import time
|
1434
|
+
|
1435
|
+
# Define the request model here since we need pydantic
|
1436
|
+
class AgentQuery(BaseModel):
|
1437
|
+
query: str
|
1438
|
+
|
1439
|
+
except ImportError as e:
|
1440
|
+
# Check which specific module is missing
|
1441
|
+
missing_module = str(e).split("No module named '")[-1].rstrip("'")
|
1442
|
+
display_error(f"Missing dependency: {missing_module}. Required for launch() method.")
|
1443
|
+
logging.error(f"Missing dependency: {missing_module}. Required for launch() method.")
|
1444
|
+
print(f"\nTo add API capabilities, install the required dependencies:")
|
1445
|
+
print(f"pip install {missing_module}")
|
1446
|
+
print("\nOr install all API dependencies with:")
|
1447
|
+
print("pip install 'praisonaiagents[api]'")
|
1448
|
+
return None
|
1449
|
+
|
1450
|
+
# Initialize shared FastAPI app if not already created
|
1451
|
+
if _shared_app is None:
|
1452
|
+
_shared_app = FastAPI(
|
1453
|
+
title="PraisonAI Agents API",
|
1454
|
+
description="API for interacting with PraisonAI Agents"
|
1455
|
+
)
|
1456
|
+
|
1457
|
+
# Add a root endpoint with a welcome message
|
1458
|
+
@_shared_app.get("/")
|
1459
|
+
async def root():
|
1460
|
+
return {"message": "Welcome to PraisonAI Agents API. See /docs for usage."}
|
1461
|
+
|
1462
|
+
# Add healthcheck endpoint
|
1463
|
+
@_shared_app.get("/health")
|
1464
|
+
async def healthcheck():
|
1465
|
+
return {"status": "ok", "agents": list(_registered_agents.keys())}
|
1466
|
+
|
1467
|
+
# Normalize path to ensure it starts with /
|
1468
|
+
if not path.startswith('/'):
|
1469
|
+
path = f'/{path}'
|
1470
|
+
|
1471
|
+
# Check if path is already registered by another agent
|
1472
|
+
if path in _registered_agents and _registered_agents[path] != self.agent_id:
|
1473
|
+
existing_agent = _registered_agents[path]
|
1474
|
+
logging.warning(f"Path '{path}' is already registered by another agent. Please use a different path.")
|
1475
|
+
print(f"⚠️ Warning: Path '{path}' is already registered by another agent.")
|
1476
|
+
# Use a modified path to avoid conflicts
|
1477
|
+
original_path = path
|
1478
|
+
path = f"{path}_{self.agent_id[:6]}"
|
1479
|
+
logging.warning(f"Using '{path}' instead of '{original_path}'")
|
1480
|
+
print(f"🔄 Using '{path}' instead")
|
1481
|
+
|
1482
|
+
# Register the agent to this path
|
1483
|
+
_registered_agents[path] = self.agent_id
|
1484
|
+
|
1485
|
+
# Define the endpoint handler
|
1486
|
+
@_shared_app.post(path)
|
1487
|
+
async def handle_agent_query(request: Request, query_data: Optional[AgentQuery] = None):
|
1488
|
+
# Handle both direct JSON with query field and form data
|
1489
|
+
if query_data is None:
|
1490
|
+
try:
|
1491
|
+
request_data = await request.json()
|
1492
|
+
if "query" not in request_data:
|
1493
|
+
raise HTTPException(status_code=400, detail="Missing 'query' field in request")
|
1494
|
+
query = request_data["query"]
|
1495
|
+
except:
|
1496
|
+
# Fallback to form data or query params
|
1497
|
+
form_data = await request.form()
|
1498
|
+
if "query" in form_data:
|
1499
|
+
query = form_data["query"]
|
1500
|
+
else:
|
1501
|
+
raise HTTPException(status_code=400, detail="Missing 'query' field in request")
|
1502
|
+
else:
|
1503
|
+
query = query_data.query
|
1504
|
+
|
1505
|
+
try:
|
1506
|
+
# Use async version if available, otherwise use sync version
|
1507
|
+
if asyncio.iscoroutinefunction(self.chat):
|
1508
|
+
response = await self.achat(query)
|
1509
|
+
else:
|
1510
|
+
# Run sync function in a thread to avoid blocking
|
1511
|
+
loop = asyncio.get_event_loop()
|
1512
|
+
response = await loop.run_in_executor(None, lambda: self.chat(query))
|
1513
|
+
|
1514
|
+
return {"response": response}
|
1515
|
+
except Exception as e:
|
1516
|
+
logging.error(f"Error processing query: {str(e)}", exc_info=True)
|
1517
|
+
return JSONResponse(
|
1518
|
+
status_code=500,
|
1519
|
+
content={"error": f"Error processing query: {str(e)}"}
|
1520
|
+
)
|
1521
|
+
|
1522
|
+
print(f"🚀 Agent '{self.name}' available at http://{host}:{port}{path}")
|
1523
|
+
|
1524
|
+
# Start the server if it's not already running
|
1525
|
+
if not _server_started:
|
1526
|
+
_server_started = True
|
1527
|
+
|
1528
|
+
# Start the server in a separate thread
|
1529
|
+
def run_server():
|
1530
|
+
try:
|
1531
|
+
print(f"✅ FastAPI server started at http://{host}:{port}")
|
1532
|
+
print(f"📚 API documentation available at http://{host}:{port}/docs")
|
1533
|
+
print(f"🔌 Available endpoints: {', '.join(list(_registered_agents.keys()))}")
|
1534
|
+
uvicorn.run(_shared_app, host=host, port=port, log_level="debug" if debug else "info")
|
1535
|
+
except Exception as e:
|
1536
|
+
logging.error(f"Error starting server: {str(e)}", exc_info=True)
|
1537
|
+
print(f"❌ Error starting server: {str(e)}")
|
1538
|
+
|
1539
|
+
# Run server in a background thread
|
1540
|
+
server_thread = threading.Thread(target=run_server, daemon=True)
|
1541
|
+
server_thread.start()
|
1542
|
+
|
1543
|
+
# Wait for a moment to allow the server to start and register endpoints
|
1544
|
+
time.sleep(0.5)
|
1545
|
+
else:
|
1546
|
+
# If server is already running, wait a moment to make sure the endpoint is registered
|
1547
|
+
time.sleep(0.1)
|
1548
|
+
print(f"🔌 Available endpoints: {', '.join(list(_registered_agents.keys()))}")
|
1549
|
+
|
1550
|
+
# Get the stack frame to check if this is the last launch() call in the script
|
1551
|
+
import inspect
|
1552
|
+
stack = inspect.stack()
|
1553
|
+
|
1554
|
+
# If this is called from a Python script (not interactive), try to detect if it's the last launch call
|
1555
|
+
if len(stack) > 1 and stack[1].filename.endswith('.py'):
|
1556
|
+
caller_frame = stack[1]
|
1557
|
+
caller_line = caller_frame.lineno
|
1558
|
+
|
1559
|
+
try:
|
1560
|
+
# Read the file to check if there are more launch calls after this one
|
1561
|
+
with open(caller_frame.filename, 'r') as f:
|
1562
|
+
lines = f.readlines()
|
1563
|
+
|
1564
|
+
# Check if there are more launch() calls after the current line
|
1565
|
+
has_more_launches = False
|
1566
|
+
for line in lines[caller_line:]:
|
1567
|
+
if '.launch(' in line and not line.strip().startswith('#'):
|
1568
|
+
has_more_launches = True
|
1569
|
+
break
|
1570
|
+
|
1571
|
+
# If this is the last launch call, block the main thread
|
1572
|
+
if not has_more_launches:
|
1573
|
+
try:
|
1574
|
+
print("\nAll agents registered. Press Ctrl+C to stop the server.")
|
1575
|
+
while True:
|
1576
|
+
time.sleep(1)
|
1577
|
+
except KeyboardInterrupt:
|
1578
|
+
print("\nServer stopped")
|
1579
|
+
except Exception as e:
|
1580
|
+
# If something goes wrong with detection, block anyway to be safe
|
1581
|
+
logging.error(f"Error in launch detection: {e}")
|
1582
|
+
try:
|
1583
|
+
while True:
|
1584
|
+
time.sleep(1)
|
1585
|
+
except KeyboardInterrupt:
|
1586
|
+
print("\nServer stopped")
|
1587
|
+
|
1588
|
+
return None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: praisonaiagents
|
3
|
-
Version: 0.0.
|
3
|
+
Version: 0.0.79
|
4
4
|
Summary: Praison AI agents for completing complex tasks with Self Reflection Agents
|
5
5
|
Author: Mervin Praison
|
6
6
|
Requires-Dist: pydantic
|
@@ -19,8 +19,12 @@ Requires-Dist: chonkie>=1.0.2; extra == "knowledge"
|
|
19
19
|
Provides-Extra: llm
|
20
20
|
Requires-Dist: litellm>=1.50.0; extra == "llm"
|
21
21
|
Requires-Dist: pydantic>=2.4.2; extra == "llm"
|
22
|
+
Provides-Extra: api
|
23
|
+
Requires-Dist: fastapi>=0.115.0; extra == "api"
|
24
|
+
Requires-Dist: uvicorn>=0.34.0; extra == "api"
|
22
25
|
Provides-Extra: all
|
23
26
|
Requires-Dist: praisonaiagents[memory]; extra == "all"
|
24
27
|
Requires-Dist: praisonaiagents[knowledge]; extra == "all"
|
25
28
|
Requires-Dist: praisonaiagents[llm]; extra == "all"
|
26
29
|
Requires-Dist: praisonaiagents[mcp]; extra == "all"
|
30
|
+
Requires-Dist: praisonaiagents[api]; extra == "all"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
praisonaiagents/__init__.py,sha256=Z2_rSA6mYozz0r3ioUgKzl3QV8uWRDS_QaqPg2oGjqg,1324
|
2
2
|
praisonaiagents/main.py,sha256=l29nGEbV2ReBi4szURbnH0Fk0w2F_QZTmECysyZjYcA,15066
|
3
3
|
praisonaiagents/agent/__init__.py,sha256=j0T19TVNbfZcClvpbZDDinQxZ0oORgsMrMqx16jZ-bA,128
|
4
|
-
praisonaiagents/agent/agent.py,sha256=
|
4
|
+
praisonaiagents/agent/agent.py,sha256=OOP_05mOMoHNkeElQWqH9jKOFUivlIjZ_vZJWLhIkSc,75089
|
5
5
|
praisonaiagents/agent/image_agent.py,sha256=-5MXG594HVwSpFMcidt16YBp7udtik-Cp7eXlzLE1fY,8696
|
6
6
|
praisonaiagents/agents/__init__.py,sha256=_1d6Pqyk9EoBSo7E68sKyd1jDRlN1vxvVIRpoMc0Jcw,168
|
7
7
|
praisonaiagents/agents/agents.py,sha256=uAOHyn77noFvg3sYVFRhQUuc1LDpCMpfLND8CKOXAd4,37971
|
@@ -40,7 +40,7 @@ praisonaiagents/tools/xml_tools.py,sha256=iYTMBEk5l3L3ryQ1fkUnNVYK-Nnua2Kx2S0dxN
|
|
40
40
|
praisonaiagents/tools/yaml_tools.py,sha256=uogAZrhXV9O7xvspAtcTfpKSQYL2nlOTvCQXN94-G9A,14215
|
41
41
|
praisonaiagents/tools/yfinance_tools.py,sha256=s2PBj_1v7oQnOobo2fDbQBACEHl61ftG4beG6Z979ZE,8529
|
42
42
|
praisonaiagents/tools/train/data/generatecot.py,sha256=H6bNh-E2hqL5MW6kX3hqZ05g9ETKN2-kudSjiuU_SD8,19403
|
43
|
-
praisonaiagents-0.0.
|
44
|
-
praisonaiagents-0.0.
|
45
|
-
praisonaiagents-0.0.
|
46
|
-
praisonaiagents-0.0.
|
43
|
+
praisonaiagents-0.0.79.dist-info/METADATA,sha256=kfbFrfIzL7AMat_CvuzqwaLAakTuDZ3IspnIW4T5Mwo,1149
|
44
|
+
praisonaiagents-0.0.79.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
|
45
|
+
praisonaiagents-0.0.79.dist-info/top_level.txt,sha256=_HsRddrJ23iDx5TTqVUVvXG2HeHBL5voshncAMDGjtA,16
|
46
|
+
praisonaiagents-0.0.79.dist-info/RECORD,,
|
File without changes
|
File without changes
|