Skip to content

Commit 08c2ad8

Browse files
praisonai-triage-agent[bot]MervinPraisongithub-actions[bot]
authored
feat: add marketplace tools - Pinchwork, AgentID, Joy Trust (#15)
* feat: add marketplace tools - Pinchwork, AgentID, Joy Trust (fixes #1292) Implements external agent-to-agent marketplace integrations as @tool plugins: - Pinchwork: Task delegation to agent marketplace - AgentID: Identity verification via ECDSA certificates - Joy Trust: Trust score verification before delegation Features: - Lazy imports with graceful error handling - Optional dependencies (httpx>=0.24.0) - @tool decorators for agent discovery - Comprehensive error handling and type hints - Real agentic tests for LLM integration Per AGENTS.md architecture: Tools are external integrations in PraisonAI-Tools repository with protocol-driven design. Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com> * feat: add AgentFolio behavioral trust tools - Add check_behavioral_trust for task-scoped trust scoring - Add verify_task_delegation_safety for comprehensive checks - Support SATP protocol for cross-organizational reputation - Include proper error handling and lazy httpx imports - Add tests and documentation following marketplace patterns - Update dependencies with agentfolio optional extra Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com> * feat: refactor marketplace tools to follow BaseTool pattern - Add proper BaseTool class implementations for all marketplace tools - Implement constructor with api_key parameter and env var fallbacks - Add lazy imports with proper error handling - Export tools in tools/__init__.py for discoverability - Maintain both class-based and standalone function interfaces - Follow established LumaLabs tool pattern for consistency 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com> * refactor: eliminate marketplace/tools duplication - consolidate to single source of truth - Remove duplicate marketplace/ directory (~500 lines of duplicated code) - Remove redundant test_standalone.py script - Update imports to use consolidated tools/ implementations - Maintain backward compatibility via praisonai_tools/__init__.py exports - Follow DRY principles with single BaseTool implementation - Preserve comprehensive error handling and environment variable support Fixes code duplication issue identified in PR review. Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com> --------- Co-authored-by: MervinPraison <454862+MervinPraison@users.noreply.github.com> Co-authored-by: Mervin Praison <MervinPraison@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent b790db4 commit 08c2ad8

10 files changed

Lines changed: 946 additions & 0 deletions

praisonai_tools/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,4 +134,14 @@ def __getattr__(name):
134134
# WhatsApp Tool
135135
"WhatsAppTool",
136136
"send_whatsapp_message",
137+
# Marketplace Tools
138+
"PinchworkTool",
139+
"pinchwork_delegate",
140+
"AgentIDTool",
141+
"verify_agent_identity",
142+
"JoyTrustTool",
143+
"check_trust_score",
144+
"AgentFolioTool",
145+
"check_behavioral_trust",
146+
"verify_task_delegation_safety",
137147
]

praisonai_tools/tools/__init__.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,16 @@ def __getattr__(name):
445445
"WordPressTool": "wordpress_tool",
446446
"check_wp_duplicate": "wordpress_tool",
447447
"create_wp_post": "wordpress_tool",
448+
# Marketplace Tools
449+
"PinchworkTool": "pinchwork_tool",
450+
"pinchwork_delegate": "pinchwork_tool",
451+
"AgentIDTool": "agentid_tool",
452+
"verify_agent_identity": "agentid_tool",
453+
"JoyTrustTool": "joy_trust_tool",
454+
"check_trust_score": "joy_trust_tool",
455+
"AgentFolioTool": "agentfolio_tool",
456+
"check_behavioral_trust": "agentfolio_tool",
457+
"verify_task_delegation_safety": "agentfolio_tool",
448458
}
449459

450460
if name in tool_map:
@@ -688,4 +698,14 @@ def __getattr__(name):
688698
"outlook_search_emails",
689699
"outlook_archive_email",
690700
"outlook_draft_email",
701+
# Marketplace Tools
702+
"PinchworkTool",
703+
"pinchwork_delegate",
704+
"AgentIDTool",
705+
"verify_agent_identity",
706+
"JoyTrustTool",
707+
"check_trust_score",
708+
"AgentFolioTool",
709+
"check_behavioral_trust",
710+
"verify_task_delegation_safety",
691711
]
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
"""AgentFolio Tool for PraisonAI Agents.
2+
3+
Behavioral trust verification across organizations using SATP protocol.
4+
5+
Usage:
6+
from praisonai_tools import AgentFolioTool
7+
8+
tool = AgentFolioTool()
9+
result = tool.check_behavioral_trust("agent_name", "code_review")
10+
11+
Environment Variables:
12+
AGENTFOLIO_API_KEY: AgentFolio API key (optional)
13+
"""
14+
15+
import os
16+
import logging
17+
from typing import Any, Dict, Optional, Union
18+
19+
from praisonai_tools.tools.base import BaseTool
20+
21+
logger = logging.getLogger(__name__)
22+
23+
24+
class AgentFolioTool(BaseTool):
25+
"""Tool for AgentFolio/SATP behavioral trust verification."""
26+
27+
name = "agentfolio"
28+
description = "Check behavioral trust scores using AgentFolio/SATP protocol."
29+
30+
def __init__(self, api_key: Optional[str] = None):
31+
self.api_key = api_key or os.getenv("AGENTFOLIO_API_KEY")
32+
super().__init__()
33+
34+
def run(
35+
self,
36+
action: str = "check_behavioral_trust",
37+
agent_name: Optional[str] = None,
38+
task_class: Optional[str] = None,
39+
**kwargs
40+
) -> Union[str, Dict[str, Any]]:
41+
if action == "check_behavioral_trust":
42+
return self.check_behavioral_trust(
43+
agent_name=agent_name,
44+
task_class=task_class,
45+
min_trust_score=kwargs.get("min_trust_score", 50.0),
46+
organization_filter=kwargs.get("organization_filter")
47+
)
48+
elif action == "verify_delegation_safety":
49+
return self.verify_delegation_safety(
50+
agent_name=agent_name,
51+
task_class=task_class,
52+
task_description=kwargs.get("task_description", ""),
53+
required_trust_level=kwargs.get("required_trust_level", 70.0)
54+
)
55+
return {"error": f"Unknown action: {action}"}
56+
57+
def check_behavioral_trust(
58+
self,
59+
agent_name: str,
60+
task_class: str,
61+
min_trust_score: float = 50.0,
62+
organization_filter: Optional[str] = None
63+
) -> Dict[str, Any]:
64+
"""Check an agent's behavioral trust score across organizations using SATP protocol.
65+
66+
Args:
67+
agent_name: Name/identifier of the agent to check
68+
task_class: Type of task for scoped trust (e.g., "code_review", "web_research", "data_analysis")
69+
min_trust_score: Minimum trust score threshold (0-100, default: 50.0)
70+
organization_filter: Optional filter for specific organization history
71+
72+
Returns:
73+
Dictionary with behavioral trust data
74+
"""
75+
if not agent_name or not task_class:
76+
return {
77+
"agent_name": agent_name or "",
78+
"task_class": task_class or "",
79+
"behavioral_score": 0.0,
80+
"meets_threshold": False,
81+
"cross_org_history": [],
82+
"total_tasks": 0,
83+
"success_rate": 0.0,
84+
"organizations": [],
85+
"reputation_trend": "unknown",
86+
"blockchain_verified": False,
87+
"error": "agent_name and task_class are required"
88+
}
89+
90+
try:
91+
import httpx
92+
except ImportError:
93+
return {
94+
"agent_name": agent_name,
95+
"task_class": task_class,
96+
"behavioral_score": 0.0,
97+
"meets_threshold": False,
98+
"cross_org_history": [],
99+
"total_tasks": 0,
100+
"success_rate": 0.0,
101+
"organizations": [],
102+
"reputation_trend": "unknown",
103+
"blockchain_verified": False,
104+
"error": (
105+
"httpx is required for AgentFolio/SATP integration. "
106+
"Install with: pip install praisonai-tools[marketplace] or pip install httpx"
107+
)
108+
}
109+
110+
try:
111+
with httpx.Client(timeout=30.0) as client:
112+
params = {
113+
"agent": agent_name,
114+
"task_class": task_class,
115+
"format": "satp"
116+
}
117+
if organization_filter:
118+
params["org_filter"] = organization_filter
119+
if self.api_key:
120+
params["api_key"] = self.api_key
121+
122+
response = client.get(
123+
"https://api.agentfolio.io/v1/behavioral_trust",
124+
params=params
125+
)
126+
response.raise_for_status()
127+
128+
data = response.json()
129+
behavioral_score = data.get("behavioral_score", 0.0)
130+
131+
return {
132+
"agent_name": agent_name,
133+
"task_class": task_class,
134+
"behavioral_score": behavioral_score,
135+
"meets_threshold": behavioral_score >= min_trust_score,
136+
"cross_org_history": data.get("cross_org_history", []),
137+
"total_tasks": data.get("total_tasks", 0),
138+
"success_rate": data.get("success_rate", 0.0),
139+
"organizations": data.get("organizations", []),
140+
"reputation_trend": data.get("reputation_trend", "stable"),
141+
"last_activity": data.get("last_activity"),
142+
"blockchain_verified": data.get("blockchain_verified", False),
143+
"satp_signature": data.get("satp_signature"),
144+
"error": None
145+
}
146+
147+
except httpx.RequestError as e:
148+
logger.error(f"AgentFolio request error: {e}")
149+
return {
150+
"agent_name": agent_name,
151+
"task_class": task_class,
152+
"behavioral_score": 0.0,
153+
"meets_threshold": False,
154+
"cross_org_history": [],
155+
"total_tasks": 0,
156+
"success_rate": 0.0,
157+
"organizations": [],
158+
"reputation_trend": "unknown",
159+
"blockchain_verified": False,
160+
"error": f"Connection error: {e}"
161+
}
162+
except httpx.HTTPStatusError as e:
163+
logger.error(f"AgentFolio API error: {e.response.status_code}")
164+
return {
165+
"agent_name": agent_name,
166+
"task_class": task_class,
167+
"behavioral_score": 0.0,
168+
"meets_threshold": False,
169+
"cross_org_history": [],
170+
"total_tasks": 0,
171+
"success_rate": 0.0,
172+
"organizations": [],
173+
"reputation_trend": "unknown",
174+
"blockchain_verified": False,
175+
"error": f"API error ({e.response.status_code}): {e.response.text}"
176+
}
177+
except Exception as e:
178+
logger.error(f"AgentFolio unexpected error: {e}")
179+
return {
180+
"agent_name": agent_name,
181+
"task_class": task_class,
182+
"behavioral_score": 0.0,
183+
"meets_threshold": False,
184+
"cross_org_history": [],
185+
"total_tasks": 0,
186+
"success_rate": 0.0,
187+
"organizations": [],
188+
"reputation_trend": "unknown",
189+
"blockchain_verified": False,
190+
"error": f"Unexpected error: {e}"
191+
}
192+
193+
def verify_delegation_safety(
194+
self,
195+
agent_name: str,
196+
task_class: str,
197+
task_description: str,
198+
required_trust_level: float = 70.0
199+
) -> Dict[str, Any]:
200+
"""Comprehensive safety check before delegating tasks using all trust layers."""
201+
behavioral_result = self.check_behavioral_trust(
202+
agent_name=agent_name,
203+
task_class=task_class,
204+
min_trust_score=required_trust_level
205+
)
206+
207+
if behavioral_result.get("error"):
208+
return {
209+
"safe_to_delegate": False,
210+
"behavioral_trust": 0.0,
211+
"risk_assessment": "high",
212+
"recommendations": ["Unable to verify behavioral trust - do not delegate"],
213+
"verification_layers": {"behavioral": behavioral_result},
214+
"error": f"Behavioral trust check failed: {behavioral_result['error']}"
215+
}
216+
217+
behavioral_score = behavioral_result.get("behavioral_score", 0.0)
218+
meets_threshold = behavioral_result.get("meets_threshold", False)
219+
220+
if behavioral_score >= required_trust_level and meets_threshold:
221+
risk_level = "low"
222+
safe_to_delegate = True
223+
recommendations = ["Agent meets behavioral trust requirements"]
224+
elif behavioral_score >= (required_trust_level * 0.7):
225+
risk_level = "medium"
226+
safe_to_delegate = False
227+
recommendations = [
228+
"Agent has moderate behavioral trust",
229+
"Consider additional verification or supervision",
230+
"Review cross-organizational history before delegating"
231+
]
232+
else:
233+
risk_level = "high"
234+
safe_to_delegate = False
235+
recommendations = [
236+
"Agent has insufficient behavioral trust history",
237+
"Do not delegate without direct supervision",
238+
"Consider using more trusted agents for this task type"
239+
]
240+
241+
return {
242+
"safe_to_delegate": safe_to_delegate,
243+
"behavioral_trust": behavioral_score,
244+
"risk_assessment": risk_level,
245+
"recommendations": recommendations,
246+
"verification_layers": {
247+
"behavioral": behavioral_result,
248+
"task_specific": {
249+
"task_class": task_class,
250+
"required_level": required_trust_level,
251+
"meets_requirement": meets_threshold
252+
}
253+
},
254+
"error": None
255+
}
256+
257+
258+
def check_behavioral_trust(
259+
agent_name: str,
260+
task_class: str,
261+
min_trust_score: float = 50.0,
262+
organization_filter: Optional[str] = None
263+
) -> Dict[str, Any]:
264+
"""Check an agent's behavioral trust score across organizations using SATP protocol."""
265+
return AgentFolioTool().check_behavioral_trust(
266+
agent_name=agent_name,
267+
task_class=task_class,
268+
min_trust_score=min_trust_score,
269+
organization_filter=organization_filter
270+
)
271+
272+
273+
def verify_task_delegation_safety(
274+
agent_name: str,
275+
task_class: str,
276+
task_description: str,
277+
required_trust_level: float = 70.0
278+
) -> Dict[str, Any]:
279+
"""Comprehensive safety check before delegating tasks using all trust layers."""
280+
return AgentFolioTool().verify_delegation_safety(
281+
agent_name=agent_name,
282+
task_class=task_class,
283+
task_description=task_description,
284+
required_trust_level=required_trust_level
285+
)

0 commit comments

Comments
 (0)