Skip to content

Commit

Permalink
Merge pull request #58 from blorm-network/pull/50/head
Browse files Browse the repository at this point in the history
feat: Decentralized Inference for Zerepy Agents - extra_body with chain_id
  • Loading branch information
ef95023 authored Jan 7, 2025
2 parents 855f751 + 56c8d04 commit ed9c689
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 32 deletions.
3 changes: 2 additions & 1 deletion agents/eternalai-example.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
},
{
"name": "eternalai",
"model": "unsloth/Llama-3.3-70B-Instruct-bnb-4bit"
"model": "NousResearch/Hermes-3-Llama-3.1-70B-FP8",
"chain_id": "45762"
}
],
"tasks": [
Expand Down
5 changes: 5 additions & 0 deletions agents/example.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@
"name": "anthropic",
"model": "claude-3-5-sonnet-20241022"
},
{
"name": "eternalai",
"model": "NousResearch/Hermes-3-Llama-3.1-70B-FP8",
"chain_id": "45762"
},
{
"name": "ollama",
"base_url": "http://localhost:11434",
Expand Down
57 changes: 57 additions & 0 deletions src/actions/eternalai_actions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import logging
from src.action_handler import register_action

logger = logging.getLogger("agent")

@register_action("eternai-generate")
def eternai_generate(agent, **kwargs):
"""Generate text using EternalAI models"""
agent.logger.info("\n🤖 GENERATING TEXT WITH ETERNAI")
try:
result = agent.connection_manager.perform_action(
connection_name="eternalai",
action_name="generate-text",
params=[
kwargs.get('prompt'),
kwargs.get('system_prompt', agent._construct_system_prompt()),
kwargs.get('model', None)
]
)
agent.logger.info("✅ Text generation completed!")
return result
except Exception as e:
agent.logger.error(f"❌ Text generation failed: {str(e)}")
return None

@register_action("eternai-check-model")
def eternai_check_model(agent, **kwargs):
"""Check if a specific model is available"""
agent.logger.info("\n🔍 CHECKING MODEL AVAILABILITY")
try:
result = agent.connection_manager.perform_action(
connection_name="eternalai",
action_name="check-model",
params=[kwargs.get('model')]
)
status = "available" if result else "not available"
agent.logger.info(f"Model is {status}")
return result
except Exception as e:
agent.logger.error(f"❌ Model check failed: {str(e)}")
return False

@register_action("eternai-list-models")
def eternai_list_models(agent, **kwargs):
"""List all available EternalAI models"""
agent.logger.info("\n📋 LISTING AVAILABLE MODELS")
try:
result = agent.connection_manager.perform_action(
connection_name="eternalai",
action_name="list-models",
params=[]
)
agent.logger.info("✅ Models listed successfully!")
return result
except Exception as e:
agent.logger.error(f"❌ Model listing failed: {str(e)}")
return None
54 changes: 23 additions & 31 deletions src/connections/eternalai_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,18 @@

logger = logging.getLogger(__name__)


class EternalAIConnectionError(Exception):
"""Base exception for EternalAI connection errors"""
pass


class EternalAIConfigurationError(EternalAIConnectionError):
"""Raised when there are configuration/credential issues"""
pass


class EternalAIAPIError(EternalAIConnectionError):
"""Raised when EternalAI API requests fail"""
pass


class EternalAIConnection(BaseConnection):
def __init__(self, config: Dict[str, Any]):
super().__init__(config)
Expand All @@ -36,14 +32,13 @@ def validate_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
"""Validate EternalAI configuration from JSON"""
required_fields = ["model"]
missing_fields = [field for field in required_fields if field not in config]

if missing_fields:
raise ValueError(f"Missing required configuration fields: {', '.join(missing_fields)}")

# Validate model exists (will be checked in detail during configure)

if not isinstance(config["model"], str):
raise ValueError("model must be a string")

return config

def register_actions(self) -> None:
Expand Down Expand Up @@ -77,8 +72,8 @@ def _get_client(self) -> OpenAI:
if not self._client:
api_key = os.getenv("EternalAI_API_KEY")
api_url = os.getenv("EternalAI_API_URL")
if not api_key:
raise EternalAIConfigurationError("EternalAI API key not found in environment")
if not api_key or not api_url:
raise EternalAIConfigurationError("EternalAI credentials not found in environment")
self._client = OpenAI(api_key=api_key, base_url=api_url)
return self._client

Expand All @@ -92,8 +87,8 @@ def configure(self) -> bool:
if response.lower() != 'y':
return True

print("\n📝 To get your EternalAI API credentials:")
print("1. Go to https://eternalai.org/api")
print("\n📝 To get your EternalAI credentials:")
print("1. Visit https://eternalai.org/api")
print("2. Generate an API Key")
print("3. Use API url as https://api.eternalai.org/v1/")

Expand All @@ -108,20 +103,20 @@ def configure(self) -> bool:
set_key('.env', 'EternalAI_API_KEY', api_key)
set_key('.env', 'EternalAI_API_URL', api_url)

# Validate the API key by trying to list models
# Validate credentials
client = OpenAI(api_key=api_key, base_url=api_url)
client.models.list()

print("\n✅ EternalAI API configuration successfully saved!")
print("Your API key has been stored in the .env file.")
print("Your credentials have been stored in the .env file.")
return True

except Exception as e:
logger.error(f"Configuration failed: {e}")
return False

def is_configured(self, verbose=False) -> bool:
"""Check if EternalAI API key is configured and valid"""
"""Check if EternalAI API credentials are configured and valid"""
try:
load_dotenv()
api_key = os.getenv('EternalAI_API_KEY')
Expand All @@ -142,11 +137,8 @@ def generate_text(self, prompt: str, system_prompt: str, model: str = None, **kw
"""Generate text using EternalAI models"""
try:
client = self._get_client()
model = model or self.config["model"]

# Use configured model if none provided
if not model:
model = self.config["model"]
print("model", model)
completion = client.chat.completions.create(
model=model,
messages=[
Expand All @@ -160,39 +152,40 @@ def generate_text(self, prompt: str, system_prompt: str, model: str = None, **kw
except Exception as e:
raise EternalAIAPIError(f"Text generation failed: {e}")

def check_model(self, model, **kwargs):
def check_model(self, model: str, **kwargs) -> bool:
"""Check if a specific model is available"""
try:
client = self._get_client
client = self._get_client()
try:
client.models.retrieve(model=model)
# If we get here, the model exists
return True
except Exception:
return False
except Exception as e:
raise EternalAIAPIError(e)
raise EternalAIAPIError(f"Model check failed: {e}")

def list_models(self, **kwargs) -> None:
"""List all available EternalAI models"""
try:
client = self._get_client()
response = client.models.list().data
#

# Filter for fine-tuned models
fine_tuned_models = [
model for model in response
model for model in response
if model.owned_by in ["organization", "user", "organization-owner"]
]
#

if fine_tuned_models:
logger.info("\nFINE-TUNED MODELS:")
for i, model in enumerate(fine_tuned_models):
logger.info(f"{i + 1}. {model.id}")

logger.info(f"{i+1}. {model.id}")
except Exception as e:
raise EternalAIAPIError(f"Listing models failed: {e}")

def perform_action(self, action_name: str, kwargs) -> Any:
"""Execute a Twitter action with validation"""
"""Execute an action with validation"""
if action_name not in self.actions:
raise KeyError(f"Unknown action: {action_name}")

Expand All @@ -201,7 +194,6 @@ def perform_action(self, action_name: str, kwargs) -> Any:
if errors:
raise ValueError(f"Invalid parameters: {', '.join(errors)}")

# Call the appropriate method based on action name
method_name = action_name.replace('-', '_')
method = getattr(self, method_name)
return method(**kwargs)
return method(**kwargs)

0 comments on commit ed9c689

Please sign in to comment.