parent
5e4a600d47
commit
d44fbcd700
@ -0,0 +1,43 @@
|
||||
# Swarms Tools Example with HTX + CoinGecko
|
||||
|
||||
- `pip3 install swarms swarms-tools`
|
||||
- Add `OPENAI_API_KEY` to your `.env` file
|
||||
- Run `swarms_tools_htx_gecko.py`
|
||||
- Agent will make a function call to the desired tool
|
||||
- The tool will be executed and the result will be returned to the agent
|
||||
- The agent will then analyze the result and return the final output
|
||||
|
||||
|
||||
```python
|
||||
from swarms import Agent
|
||||
from swarms.prompts.finance_agent_sys_prompt import (
|
||||
FINANCIAL_AGENT_SYS_PROMPT,
|
||||
)
|
||||
from swarms_tools import (
|
||||
fetch_stock_news,
|
||||
coin_gecko_coin_api,
|
||||
fetch_htx_data,
|
||||
)
|
||||
|
||||
# Initialize the agent
|
||||
agent = Agent(
|
||||
agent_name="Financial-Analysis-Agent",
|
||||
agent_description="Personal finance advisor agent",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=1,
|
||||
model_name="gpt-4o",
|
||||
dynamic_temperature_enabled=True,
|
||||
user_name="swarms_corp",
|
||||
retry_attempts=3,
|
||||
context_length=8192,
|
||||
return_step_meta=False,
|
||||
output_type="str", # "json", "dict", "csv" OR "string" "yaml" and
|
||||
auto_generate_prompt=False, # Auto generate prompt for the agent based on name, description, and system prompt, task
|
||||
max_tokens=4000, # max output tokens
|
||||
saved_state_path="agent_00.json",
|
||||
interactive=False,
|
||||
tools=[fetch_stock_news, coin_gecko_coin_api, fetch_htx_data],
|
||||
)
|
||||
|
||||
agent.run("Analyze the $swarms token on htx")
|
||||
```
|
@ -0,0 +1,33 @@
|
||||
from swarms.utils.formatter import formatter
|
||||
|
||||
|
||||
def agent_print(
|
||||
agent_name: str,
|
||||
response: str = None,
|
||||
loop_count: int = None,
|
||||
streaming_on: bool = False,
|
||||
):
|
||||
"""
|
||||
Prints the response from an agent based on the streaming mode.
|
||||
|
||||
Args:
|
||||
agent_name (str): The name of the agent.
|
||||
response (str): The response from the agent.
|
||||
loop_count (int): The maximum number of loops.
|
||||
streaming_on (bool): Indicates if streaming is on or off.
|
||||
|
||||
Returns:
|
||||
str: The response from the agent.
|
||||
"""
|
||||
if streaming_on:
|
||||
formatter.print_panel_token_by_token(
|
||||
f"{agent_name}: {response}",
|
||||
title=f"Agent Name: {agent_name} [Max Loops: {loop_count}]",
|
||||
)
|
||||
else:
|
||||
formatter.print_panel(
|
||||
f"{agent_name}: {response}",
|
||||
f"Agent Name {agent_name} [Max Loops: {loop_count} ]",
|
||||
)
|
||||
|
||||
return response
|
@ -0,0 +1,318 @@
|
||||
import base64
|
||||
import json
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Union, Dict, List
|
||||
|
||||
from cryptography.fernet import Fernet
|
||||
from cryptography.hazmat.primitives import hashes, serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
||||
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
|
||||
|
||||
|
||||
@dataclass
|
||||
class EncryptedMessage:
|
||||
"""Structure for encrypted messages between agents"""
|
||||
|
||||
sender_id: str
|
||||
receiver_id: str
|
||||
encrypted_content: bytes
|
||||
timestamp: float
|
||||
message_id: str
|
||||
session_id: str
|
||||
|
||||
|
||||
class EncryptionSession:
|
||||
"""Represents an encrypted communication session between agents"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
session_id: str,
|
||||
agent_ids: List[str],
|
||||
encrypted_keys: Dict[str, bytes],
|
||||
created_at: datetime,
|
||||
):
|
||||
self.session_id = session_id
|
||||
self.agent_ids = agent_ids
|
||||
self.encrypted_keys = encrypted_keys
|
||||
self.created_at = created_at
|
||||
|
||||
|
||||
class AgentEncryption:
|
||||
"""
|
||||
Handles encryption for agent data both at rest and in transit.
|
||||
Supports both symmetric (for data at rest) and asymmetric (for data in transit) encryption.
|
||||
Also supports secure multi-agent communication.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
agent_id: Optional[str] = None,
|
||||
encryption_key: Optional[str] = None,
|
||||
enable_transit_encryption: bool = False,
|
||||
enable_rest_encryption: bool = False,
|
||||
enable_multi_agent: bool = False,
|
||||
):
|
||||
self.agent_id = agent_id or str(uuid.uuid4())
|
||||
self.enable_transit_encryption = enable_transit_encryption
|
||||
self.enable_rest_encryption = enable_rest_encryption
|
||||
self.enable_multi_agent = enable_multi_agent
|
||||
|
||||
# Multi-agent communication storage
|
||||
self.sessions: Dict[str, EncryptionSession] = {}
|
||||
self.known_agents: Dict[str, "AgentEncryption"] = {}
|
||||
|
||||
if enable_rest_encryption:
|
||||
# Initialize encryption for data at rest
|
||||
if encryption_key:
|
||||
self.encryption_key = base64.urlsafe_b64encode(
|
||||
PBKDF2HMAC(
|
||||
algorithm=hashes.SHA256(),
|
||||
length=32,
|
||||
salt=f"agent_{self.agent_id}".encode(), # Unique salt per agent
|
||||
iterations=100000,
|
||||
).derive(encryption_key.encode())
|
||||
)
|
||||
else:
|
||||
self.encryption_key = Fernet.generate_key()
|
||||
|
||||
self.cipher_suite = Fernet(self.encryption_key)
|
||||
|
||||
if enable_transit_encryption or enable_multi_agent:
|
||||
# Generate RSA key pair for transit encryption
|
||||
self.private_key = rsa.generate_private_key(
|
||||
public_exponent=65537, key_size=2048
|
||||
)
|
||||
self.public_key = self.private_key.public_key()
|
||||
|
||||
def register_agent(
|
||||
self, agent_id: str, agent_encryption: "AgentEncryption"
|
||||
) -> None:
|
||||
"""Register another agent for secure communication"""
|
||||
if not self.enable_multi_agent:
|
||||
raise ValueError("Multi-agent support is not enabled")
|
||||
self.known_agents[agent_id] = agent_encryption
|
||||
|
||||
def create_session(self, agent_ids: List[str]) -> str:
|
||||
"""Create a new encrypted session between multiple agents"""
|
||||
if not self.enable_multi_agent:
|
||||
raise ValueError("Multi-agent support is not enabled")
|
||||
|
||||
session_id = str(uuid.uuid4())
|
||||
|
||||
# Generate a shared session key
|
||||
session_key = Fernet.generate_key()
|
||||
|
||||
# Create encrypted copies of the session key for each agent
|
||||
encrypted_keys = {}
|
||||
for agent_id in agent_ids:
|
||||
if (
|
||||
agent_id not in self.known_agents
|
||||
and agent_id != self.agent_id
|
||||
):
|
||||
raise ValueError(f"Agent {agent_id} not registered")
|
||||
|
||||
if agent_id == self.agent_id:
|
||||
agent_public_key = self.public_key
|
||||
else:
|
||||
agent_public_key = self.known_agents[
|
||||
agent_id
|
||||
].public_key
|
||||
|
||||
encrypted_key = agent_public_key.encrypt(
|
||||
session_key,
|
||||
padding.OAEP(
|
||||
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
algorithm=hashes.SHA256(),
|
||||
label=None,
|
||||
),
|
||||
)
|
||||
encrypted_keys[agent_id] = encrypted_key
|
||||
|
||||
# Store session information
|
||||
self.sessions[session_id] = EncryptionSession(
|
||||
session_id=session_id,
|
||||
agent_ids=agent_ids,
|
||||
encrypted_keys=encrypted_keys,
|
||||
created_at=datetime.now(),
|
||||
)
|
||||
|
||||
return session_id
|
||||
|
||||
def encrypt_message(
|
||||
self,
|
||||
content: Union[str, dict],
|
||||
receiver_id: str,
|
||||
session_id: str,
|
||||
) -> EncryptedMessage:
|
||||
"""Encrypt a message for another agent within a session"""
|
||||
if not self.enable_multi_agent:
|
||||
raise ValueError("Multi-agent support is not enabled")
|
||||
|
||||
if session_id not in self.sessions:
|
||||
raise ValueError("Invalid session ID")
|
||||
|
||||
session = self.sessions[session_id]
|
||||
if (
|
||||
self.agent_id not in session.agent_ids
|
||||
or receiver_id not in session.agent_ids
|
||||
):
|
||||
raise ValueError("Sender or receiver not in session")
|
||||
|
||||
# Serialize content if it's a dictionary
|
||||
if isinstance(content, dict):
|
||||
content = json.dumps(content)
|
||||
|
||||
# Get the session key
|
||||
encrypted_session_key = session.encrypted_keys[self.agent_id]
|
||||
session_key = self.decrypt_session_key(encrypted_session_key)
|
||||
|
||||
# Create Fernet cipher with session key
|
||||
cipher = Fernet(session_key)
|
||||
|
||||
# Encrypt the message
|
||||
encrypted_content = cipher.encrypt(content.encode())
|
||||
|
||||
return EncryptedMessage(
|
||||
sender_id=self.agent_id,
|
||||
receiver_id=receiver_id,
|
||||
encrypted_content=encrypted_content,
|
||||
timestamp=datetime.now().timestamp(),
|
||||
message_id=str(uuid.uuid4()),
|
||||
session_id=session_id,
|
||||
)
|
||||
|
||||
def decrypt_message(
|
||||
self, message: EncryptedMessage
|
||||
) -> Union[str, dict]:
|
||||
"""Decrypt a message from another agent"""
|
||||
if not self.enable_multi_agent:
|
||||
raise ValueError("Multi-agent support is not enabled")
|
||||
|
||||
if message.session_id not in self.sessions:
|
||||
raise ValueError("Invalid session ID")
|
||||
|
||||
if self.agent_id != message.receiver_id:
|
||||
raise ValueError("Message not intended for this agent")
|
||||
|
||||
session = self.sessions[message.session_id]
|
||||
|
||||
# Get the session key
|
||||
encrypted_session_key = session.encrypted_keys[self.agent_id]
|
||||
session_key = self.decrypt_session_key(encrypted_session_key)
|
||||
|
||||
# Create Fernet cipher with session key
|
||||
cipher = Fernet(session_key)
|
||||
|
||||
# Decrypt the message
|
||||
decrypted_content = cipher.decrypt(
|
||||
message.encrypted_content
|
||||
).decode()
|
||||
|
||||
# Try to parse as JSON
|
||||
try:
|
||||
return json.loads(decrypted_content)
|
||||
except json.JSONDecodeError:
|
||||
return decrypted_content
|
||||
|
||||
def decrypt_session_key(self, encrypted_key: bytes) -> bytes:
|
||||
"""Decrypt a session key using the agent's private key"""
|
||||
return self.private_key.decrypt(
|
||||
encrypted_key,
|
||||
padding.OAEP(
|
||||
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
algorithm=hashes.SHA256(),
|
||||
label=None,
|
||||
),
|
||||
)
|
||||
|
||||
# Original methods preserved below
|
||||
def encrypt_at_rest(self, data: Union[str, dict, bytes]) -> bytes:
|
||||
"""Encrypts data for storage"""
|
||||
if not self.enable_rest_encryption:
|
||||
return (
|
||||
data
|
||||
if isinstance(data, bytes)
|
||||
else str(data).encode()
|
||||
)
|
||||
|
||||
if isinstance(data, dict):
|
||||
data = json.dumps(data)
|
||||
if isinstance(data, str):
|
||||
data = data.encode()
|
||||
|
||||
return self.cipher_suite.encrypt(data)
|
||||
|
||||
def decrypt_at_rest(
|
||||
self, encrypted_data: bytes
|
||||
) -> Union[str, dict]:
|
||||
"""Decrypts stored data"""
|
||||
if not self.enable_rest_encryption:
|
||||
return encrypted_data.decode()
|
||||
|
||||
decrypted_data = self.cipher_suite.decrypt(encrypted_data)
|
||||
|
||||
try:
|
||||
return json.loads(decrypted_data)
|
||||
except json.JSONDecodeError:
|
||||
return decrypted_data.decode()
|
||||
|
||||
def encrypt_for_transit(self, data: Union[str, dict]) -> bytes:
|
||||
"""Encrypts data for transmission"""
|
||||
if not self.enable_transit_encryption:
|
||||
return str(data).encode()
|
||||
|
||||
if isinstance(data, dict):
|
||||
data = json.dumps(data)
|
||||
|
||||
return self.public_key.encrypt(
|
||||
data.encode(),
|
||||
padding.OAEP(
|
||||
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
algorithm=hashes.SHA256(),
|
||||
label=None,
|
||||
),
|
||||
)
|
||||
|
||||
def decrypt_from_transit(
|
||||
self, data: Union[bytes, str]
|
||||
) -> Union[str, dict]:
|
||||
"""Decrypts received data, handling both encrypted and unencrypted inputs"""
|
||||
if not self.enable_transit_encryption:
|
||||
return data.decode() if isinstance(data, bytes) else data
|
||||
|
||||
try:
|
||||
if isinstance(data, bytes) and len(data) == 256:
|
||||
decrypted_data = self.private_key.decrypt(
|
||||
data,
|
||||
padding.OAEP(
|
||||
mgf=padding.MGF1(algorithm=hashes.SHA256()),
|
||||
algorithm=hashes.SHA256(),
|
||||
label=None,
|
||||
),
|
||||
).decode()
|
||||
else:
|
||||
return (
|
||||
data.decode() if isinstance(data, bytes) else data
|
||||
)
|
||||
|
||||
try:
|
||||
return json.loads(decrypted_data)
|
||||
except json.JSONDecodeError:
|
||||
return decrypted_data
|
||||
except ValueError:
|
||||
return data.decode() if isinstance(data, bytes) else data
|
||||
|
||||
def get_public_key_pem(self) -> bytes:
|
||||
"""Returns the public key in PEM format for sharing"""
|
||||
if (
|
||||
not self.enable_transit_encryption
|
||||
and not self.enable_multi_agent
|
||||
):
|
||||
return b""
|
||||
|
||||
return self.public_key.public_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
||||
)
|
@ -0,0 +1,30 @@
|
||||
from swarms import Agent
|
||||
from swarms.prompts.finance_agent_sys_prompt import (
|
||||
FINANCIAL_AGENT_SYS_PROMPT,
|
||||
)
|
||||
from swarms_tools import (
|
||||
coin_gecko_coin_api,
|
||||
fetch_htx_data,
|
||||
)
|
||||
|
||||
|
||||
# Initialize the agent
|
||||
agent = Agent(
|
||||
agent_name="Financial-Analysis-Agent",
|
||||
agent_description="Personal finance advisor agent",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=1,
|
||||
model_name="gpt-4o",
|
||||
dynamic_temperature_enabled=True,
|
||||
user_name="swarms_corp",
|
||||
return_step_meta=False,
|
||||
output_type="str", # "json", "dict", "csv" OR "string" "yaml" and
|
||||
auto_generate_prompt=False, # Auto generate prompt for the agent based on name, description, and system prompt, task
|
||||
max_tokens=4000, # max output tokens
|
||||
saved_state_path="agent_00.json",
|
||||
interactive=False,
|
||||
)
|
||||
|
||||
agent.run(
|
||||
f"Analyze the $swarms token on HTX with data: {fetch_htx_data('swarms')}. Additionally, consider the following CoinGecko data: {coin_gecko_coin_api('swarms')}"
|
||||
)
|
@ -0,0 +1,92 @@
|
||||
# Define a simple testing framework
|
||||
from swarms.tools.tool_parse_exec import parse_and_execute_json
|
||||
|
||||
|
||||
def run_test(test_name, test_func):
|
||||
print(f"Running test: {test_name}")
|
||||
print("------------------------------------------------")
|
||||
try:
|
||||
test_func()
|
||||
print(f"✓ {test_name} passed")
|
||||
print("------------------------------------------------")
|
||||
except Exception as e:
|
||||
print(f"✗ {test_name} failed: {str(e)}")
|
||||
print("------------------------------------------------")
|
||||
|
||||
|
||||
# Mock functions for testing
|
||||
def mock_function_a(param1, param2):
|
||||
return param1 + param2
|
||||
|
||||
|
||||
def mock_function_b(param1):
|
||||
if param1 < 0:
|
||||
raise ValueError("Negative value not allowed")
|
||||
return param1 * 2
|
||||
|
||||
|
||||
# Test cases
|
||||
def test_parse_and_execute_json_success():
|
||||
functions = [mock_function_a, mock_function_b]
|
||||
json_string = '{"functions": [{"name": "mock_function_a", "parameters": {"param1": 1, "param2": 2}}, {"name": "mock_function_b", "parameters": {"param1": 3}}]}'
|
||||
|
||||
result = parse_and_execute_json(functions, json_string)
|
||||
expected_result = {
|
||||
"results": {"mock_function_a": "3", "mock_function_b": "6"},
|
||||
"summary": "mock_function_a: 3\nmock_function_b: 6",
|
||||
}
|
||||
|
||||
assert (
|
||||
result == expected_result
|
||||
), f"Expected {expected_result}, but got {result}"
|
||||
|
||||
|
||||
def test_parse_and_execute_json_function_not_found():
|
||||
functions = [mock_function_a]
|
||||
json_string = '{"functions": [{"name": "non_existent_function", "parameters": {}}]}'
|
||||
|
||||
result = parse_and_execute_json(functions, json_string)
|
||||
expected_result = {
|
||||
"results": {
|
||||
"non_existent_function": "Error: Function non_existent_function not found"
|
||||
},
|
||||
"summary": "non_existent_function: Error: Function non_existent_function not found",
|
||||
}
|
||||
|
||||
assert (
|
||||
result == expected_result
|
||||
), f"Expected {expected_result}, but got {result}"
|
||||
|
||||
|
||||
def test_parse_and_execute_json_error_handling():
|
||||
functions = [mock_function_b]
|
||||
json_string = '{"functions": [{"name": "mock_function_b", "parameters": {"param1": -1}}]}'
|
||||
|
||||
result = parse_and_execute_json(functions, json_string)
|
||||
expected_result = {
|
||||
"results": {
|
||||
"mock_function_b": "Error: Negative value not allowed"
|
||||
},
|
||||
"summary": "mock_function_b: Error: Negative value not allowed",
|
||||
}
|
||||
|
||||
assert (
|
||||
result == expected_result
|
||||
), f"Expected {expected_result}, but got {result}"
|
||||
|
||||
|
||||
# Run tests
|
||||
run_test(
|
||||
"Test parse_and_execute_json success",
|
||||
test_parse_and_execute_json_success,
|
||||
)
|
||||
print("------------------------------------------------")
|
||||
run_test(
|
||||
"Test parse_and_execute_json function not found",
|
||||
test_parse_and_execute_json_function_not_found,
|
||||
)
|
||||
print("------------------------------------------------")
|
||||
run_test(
|
||||
"Test parse_and_execute_json error handling",
|
||||
test_parse_and_execute_json_error_handling,
|
||||
)
|
Loading…
Reference in new issue