feat: add certificate verification functionality
This commit is contained in:
parent
eb0121b787
commit
cea3411911
97
.env.example
97
.env.example
|
|
@ -1,17 +1,100 @@
|
||||||
# Trading Agents Environment Variables
|
# TradingAgents Environment Configuration
|
||||||
# Copy this file to .env and fill in your values
|
# Copy this file to .env and fill in your values
|
||||||
|
|
||||||
# Finnhub API Key (required for market data)
|
# =============================================================================
|
||||||
|
# API Keys (Required)
|
||||||
|
# =============================================================================
|
||||||
|
OPENAI_API_KEY=your_openai_api_key_here
|
||||||
FINNHUB_API_KEY=your_finnhub_api_key_here
|
FINNHUB_API_KEY=your_finnhub_api_key_here
|
||||||
|
|
||||||
# OpenAI API Key (required for AI processing)
|
# Optional API Keys
|
||||||
OPENAI_API_KEY=your_openai_api_key_here
|
OPENROUTER_API_KEY=your_openrouter_api_key_here
|
||||||
|
GOOGLE_API_KEY=your_google_api_key_here
|
||||||
|
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||||
|
|
||||||
# Reddit API Credentials (required for social media analysis)
|
# Reddit API (Optional - for social media analysis)
|
||||||
REDDIT_CLIENT_ID=your_reddit_client_id_here
|
REDDIT_CLIENT_ID=your_reddit_client_id
|
||||||
REDDIT_CLIENT_SECRET=your_reddit_client_secret_here
|
REDDIT_CLIENT_SECRET=your_reddit_client_secret
|
||||||
REDDIT_USER_AGENT=TradingAgents/1.0
|
REDDIT_USER_AGENT=TradingAgents/1.0
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SSL/TLS Certificate Configuration (OPTIONAL)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Certificate Bundle Path (ONLY set if you need a custom certificate bundle)
|
||||||
|
# If not set, system default SSL behavior is used
|
||||||
|
# Common locations:
|
||||||
|
# - macOS: /etc/ssl/cert.pem
|
||||||
|
# - Ubuntu/Debian: /etc/ssl/certs/ca-certificates.crt
|
||||||
|
# - CentOS/RHEL: /etc/pki/tls/certs/ca-bundle.crt
|
||||||
|
# - Custom: /path/to/your/custom-ca-bundle.crt
|
||||||
|
# REQUESTS_CA_BUNDLE=/etc/ssl/cert.pem
|
||||||
|
# CURL_CA_BUNDLE=/etc/ssl/cert.pem
|
||||||
|
|
||||||
|
# SSL Verification (ONLY set to false if needed for development/testing)
|
||||||
|
# If not set, SSL verification is enabled by default (recommended)
|
||||||
|
# SSL_VERIFY=false
|
||||||
|
|
||||||
|
# HTTP Timeout (ONLY set if default timeout is insufficient)
|
||||||
|
# If not set, uses reasonable defaults
|
||||||
|
# HTTP_TIMEOUT=60
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Proxy Configuration (ONLY if behind corporate firewall)
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# HTTP/HTTPS Proxy Settings (ONLY set if required by your network)
|
||||||
|
# If not set, direct connections are used
|
||||||
|
# HTTP_PROXY=http://proxy.company.com:8080
|
||||||
|
# HTTPS_PROXY=https://proxy.company.com:8080
|
||||||
|
|
||||||
|
# Proxy with authentication
|
||||||
|
# HTTP_PROXY=http://username:password@proxy.company.com:8080
|
||||||
|
# HTTPS_PROXY=https://username:password@proxy.company.com:8080
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Application Settings
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Results Directory
|
||||||
|
TRADINGAGENTS_RESULTS_DIR=./results
|
||||||
|
|
||||||
|
# Ollama Configuration (if using local Ollama)
|
||||||
|
OLLAMA_HOST=localhost
|
||||||
|
|
||||||
# Optional Configuration
|
# Optional Configuration
|
||||||
# DEBUG=True
|
# DEBUG=True
|
||||||
# LOG_LEVEL=INFO
|
# LOG_LEVEL=INFO
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# SSL Certificate Examples for Common Enterprise Environments
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# Example 1: Using system certificate store (macOS)
|
||||||
|
# REQUESTS_CA_BUNDLE=/System/Library/OpenSSL/certs/cert.pem
|
||||||
|
|
||||||
|
# Example 2: Using system certificate store (Ubuntu/Debian)
|
||||||
|
# REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# Example 3: Using custom corporate certificate bundle
|
||||||
|
# REQUESTS_CA_BUNDLE=/usr/local/share/ca-certificates/corporate-ca-bundle.crt
|
||||||
|
|
||||||
|
# Example 4: Disabling SSL verification (development only)
|
||||||
|
# SSL_VERIFY=false
|
||||||
|
|
||||||
|
# =============================================================================
|
||||||
|
# Troubleshooting SSL Issues
|
||||||
|
# =============================================================================
|
||||||
|
|
||||||
|
# If you encounter SSL certificate errors:
|
||||||
|
# 1. Run the diagnostic tool: python diagnose_ssl.py
|
||||||
|
# 2. Check if your organization uses a custom CA
|
||||||
|
# 3. Ask your IT department for the corporate certificate bundle
|
||||||
|
# 4. Try using certifi's bundle: pip install certifi
|
||||||
|
# 5. Set REQUESTS_CA_BUNDLE to certifi's location (usually shown by diagnose_ssl.py)
|
||||||
|
|
||||||
|
# Common SSL Error Solutions:
|
||||||
|
# - "certificate verify failed": Set REQUESTS_CA_BUNDLE to correct cert bundle
|
||||||
|
# - "SSL: WRONG_VERSION_NUMBER": Check if you're behind a proxy
|
||||||
|
# - "Connection timeout": Increase HTTP_TIMEOUT or check proxy settings
|
||||||
|
# - "Name or service not known": Check DNS settings and proxy configuration
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
# SSL Certificate Bundle Configuration for TradingAgents
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This implementation provides flexible SSL/TLS certificate configuration for TradingAgents while maintaining backward compatibility. The system only applies custom SSL settings when explicitly configured via environment variables.
|
||||||
|
|
||||||
|
## Key Features
|
||||||
|
|
||||||
|
### 1. Environment Variable Based Configuration
|
||||||
|
- `REQUESTS_CA_BUNDLE` or `CURL_CA_BUNDLE`: Path to custom certificate bundle
|
||||||
|
- `SSL_VERIFY`: Enable/disable SSL verification (true/false)
|
||||||
|
- `HTTP_TIMEOUT`: Custom timeout for HTTP requests (seconds)
|
||||||
|
- `HTTP_PROXY`: HTTP proxy server
|
||||||
|
- `HTTPS_PROXY`: HTTPS proxy server
|
||||||
|
|
||||||
|
### 2. Default Behavior Preservation
|
||||||
|
- **If no environment variables are set**: Uses system default SSL behavior
|
||||||
|
- **Only applies custom settings when explicitly configured**
|
||||||
|
- **Empty or undefined variables are ignored**
|
||||||
|
|
||||||
|
### 3. Comprehensive Coverage
|
||||||
|
- **LangChain LLM clients**: Custom SSL configuration for OpenAI, OpenRouter, etc.
|
||||||
|
- **HTTP requests**: Custom configuration for Google News, Reddit APIs
|
||||||
|
- **Global SSL setup**: Sets environment variables for libraries that respect them
|
||||||
|
|
||||||
|
## Usage Examples
|
||||||
|
|
||||||
|
### Basic Usage (No Custom SSL)
|
||||||
|
```bash
|
||||||
|
# No SSL environment variables set
|
||||||
|
# Uses system default SSL behavior
|
||||||
|
python webapp/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Certificate Bundle
|
||||||
|
```bash
|
||||||
|
# Use custom corporate certificate bundle
|
||||||
|
export REQUESTS_CA_BUNDLE=/path/to/corporate-ca-bundle.crt
|
||||||
|
python webapp/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development/Testing (Disable SSL Verification)
|
||||||
|
```bash
|
||||||
|
# Disable SSL verification (NOT recommended for production)
|
||||||
|
export SSL_VERIFY=false
|
||||||
|
python webapp/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Behind Corporate Proxy
|
||||||
|
```bash
|
||||||
|
# Configure proxy settings
|
||||||
|
export HTTP_PROXY=http://proxy.company.com:8080
|
||||||
|
export HTTPS_PROXY=https://proxy.company.com:8080
|
||||||
|
export REQUESTS_CA_BUNDLE=/etc/ssl/corporate-ca-bundle.crt
|
||||||
|
python webapp/main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Files Modified
|
||||||
|
|
||||||
|
### Core Configuration
|
||||||
|
- `tradingagents/default_config.py`: Added SSL configuration parameters
|
||||||
|
- `tradingagents/dataflows/ssl_utils.py`: SSL utility functions (NEW)
|
||||||
|
|
||||||
|
### Integration Points
|
||||||
|
- `tradingagents/graph/trading_graph.py`: LLM client SSL configuration
|
||||||
|
- `tradingagents/dataflows/googlenews_utils.py`: HTTP requests SSL configuration
|
||||||
|
- `tradingagents/dataflows/interface.py`: Integration with SSL configuration
|
||||||
|
|
||||||
|
### Documentation and Tools
|
||||||
|
- `.env.example`: Updated with SSL configuration examples
|
||||||
|
- `diagnose_ssl.py`: SSL diagnostic tool (NEW)
|
||||||
|
- `test_ssl_config.py`: SSL configuration test suite (NEW)
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
Run the diagnostic tool to check your SSL configuration:
|
||||||
|
```bash
|
||||||
|
python diagnose_ssl.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the test suite to verify SSL configuration behavior:
|
||||||
|
```bash
|
||||||
|
python test_ssl_config.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common SSL Errors and Solutions
|
||||||
|
|
||||||
|
1. **Certificate verification failed**
|
||||||
|
- Set `REQUESTS_CA_BUNDLE` to correct certificate bundle path
|
||||||
|
- Check if your organization uses custom CA certificates
|
||||||
|
|
||||||
|
2. **SSL: WRONG_VERSION_NUMBER**
|
||||||
|
- Usually indicates proxy configuration issues
|
||||||
|
- Set appropriate `HTTP_PROXY` and `HTTPS_PROXY` variables
|
||||||
|
|
||||||
|
3. **Connection timeout**
|
||||||
|
- Increase `HTTP_TIMEOUT` value
|
||||||
|
- Check network connectivity and proxy settings
|
||||||
|
|
||||||
|
4. **Name or service not known**
|
||||||
|
- Check DNS settings
|
||||||
|
- Verify proxy configuration
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
|
||||||
|
1. Run `python diagnose_ssl.py` for comprehensive SSL diagnostics
|
||||||
|
2. Check your organization's IT documentation for certificate bundles
|
||||||
|
3. Contact your IT department for corporate proxy and certificate information
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- **Never disable SSL verification in production**
|
||||||
|
- **Use custom certificate bundles for corporate environments**
|
||||||
|
- **Keep certificate bundles updated**
|
||||||
|
- **Secure proxy credentials if using authenticated proxies**
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Certificate Bundle Combiner for TradingAgents
|
||||||
|
|
||||||
|
This script combines your corporate certificate bundle (Netskope) with
|
||||||
|
the certifi certificate bundle to ensure all certificates are available.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
def combine_certificate_bundles():
|
||||||
|
"""Combine corporate and certifi certificate bundles"""
|
||||||
|
|
||||||
|
print("🔗 Certificate Bundle Combiner")
|
||||||
|
print("=" * 40)
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
corporate_bundle = "/Users/kevin.bruton/netskope-certificates/netskope-cert-bundle.pem"
|
||||||
|
|
||||||
|
try:
|
||||||
|
import certifi
|
||||||
|
certifi_bundle = certifi.where()
|
||||||
|
except ImportError:
|
||||||
|
print("❌ certifi package not found. Please install it: pip install certifi")
|
||||||
|
return False
|
||||||
|
|
||||||
|
combined_bundle = "/Users/kevin.bruton/netskope-certificates/combined-cert-bundle.pem"
|
||||||
|
|
||||||
|
print(f"📋 Corporate bundle: {corporate_bundle}")
|
||||||
|
print(f"📋 Certifi bundle: {certifi_bundle}")
|
||||||
|
print(f"📋 Combined bundle: {combined_bundle}")
|
||||||
|
|
||||||
|
# Check if corporate bundle exists
|
||||||
|
if not os.path.exists(corporate_bundle):
|
||||||
|
print(f"❌ Corporate certificate bundle not found: {corporate_bundle}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Create combined bundle
|
||||||
|
try:
|
||||||
|
with open(combined_bundle, 'w') as combined_file:
|
||||||
|
# Write corporate certificates first
|
||||||
|
print("📝 Adding corporate certificates...")
|
||||||
|
with open(corporate_bundle, 'r') as corp_file:
|
||||||
|
combined_file.write(corp_file.read())
|
||||||
|
|
||||||
|
# Add separator
|
||||||
|
combined_file.write("\n# Certifi certificates below\n")
|
||||||
|
|
||||||
|
# Write certifi certificates
|
||||||
|
print("📝 Adding certifi certificates...")
|
||||||
|
with open(certifi_bundle, 'r') as certifi_file:
|
||||||
|
certifi_content = certifi_file.read()
|
||||||
|
combined_file.write(certifi_content)
|
||||||
|
|
||||||
|
print(f"✅ Combined certificate bundle created: {combined_bundle}")
|
||||||
|
|
||||||
|
# Set permissions
|
||||||
|
os.chmod(combined_bundle, 0o644)
|
||||||
|
|
||||||
|
# Show usage instructions
|
||||||
|
print("\n💡 Usage Instructions:")
|
||||||
|
print(f" Add this to your .env file:")
|
||||||
|
print(f" REQUESTS_CA_BUNDLE={combined_bundle}")
|
||||||
|
print(f" CURL_CA_BUNDLE={combined_bundle}")
|
||||||
|
|
||||||
|
print("\n Or export in your shell:")
|
||||||
|
print(f" export REQUESTS_CA_BUNDLE={combined_bundle}")
|
||||||
|
print(f" export CURL_CA_BUNDLE={combined_bundle}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error creating combined bundle: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
def test_combined_bundle():
|
||||||
|
"""Test the combined certificate bundle"""
|
||||||
|
combined_bundle = "/Users/kevin.bruton/netskope-certificates/combined-cert-bundle.pem"
|
||||||
|
|
||||||
|
if not os.path.exists(combined_bundle):
|
||||||
|
print("❌ Combined bundle not found. Run combine_certificate_bundles() first.")
|
||||||
|
return False
|
||||||
|
|
||||||
|
print(f"\n🧪 Testing combined certificate bundle: {combined_bundle}")
|
||||||
|
|
||||||
|
import requests
|
||||||
|
test_urls = [
|
||||||
|
"https://www.google.com",
|
||||||
|
"https://api.openai.com/v1/models",
|
||||||
|
"https://openrouter.ai/api/v1/models"
|
||||||
|
]
|
||||||
|
|
||||||
|
for url in test_urls:
|
||||||
|
try:
|
||||||
|
response = requests.get(url, verify=combined_bundle, timeout=10)
|
||||||
|
print(f"✅ {url} - Status: {response.status_code}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ {url} - Error: {e}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
if combine_certificate_bundles():
|
||||||
|
test_combined_bundle()
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Debug script to test the TradingAgentsGraph streaming behavior
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
def debug_callback(state):
|
||||||
|
"""Debug callback to see what state is being passed"""
|
||||||
|
print(f"\n🔍 CALLBACK RECEIVED:")
|
||||||
|
print(f" State type: {type(state)}")
|
||||||
|
print(f" State keys: {list(state.keys()) if isinstance(state, dict) else 'Not a dict'}")
|
||||||
|
|
||||||
|
if isinstance(state, dict):
|
||||||
|
for key, value in state.items():
|
||||||
|
if key in ["__end__", "messages"]:
|
||||||
|
continue
|
||||||
|
print(f" {key}: {type(value)} - {str(value)[:100]}...")
|
||||||
|
print("-" * 50)
|
||||||
|
|
||||||
|
def test_streaming():
|
||||||
|
"""Test the streaming functionality"""
|
||||||
|
print("🚀 Testing TradingAgentsGraph streaming...")
|
||||||
|
|
||||||
|
# Create a minimal config for testing
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
config["llm_provider"] = "openai"
|
||||||
|
config["quick_think_llm"] = "gpt-3.5-turbo"
|
||||||
|
config["deep_think_llm"] = "gpt-4"
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Initialize the graph
|
||||||
|
print("📊 Initializing TradingAgentsGraph...")
|
||||||
|
graph = TradingAgentsGraph(config=config)
|
||||||
|
|
||||||
|
# Test propagation with callback
|
||||||
|
print("🔄 Starting propagation with callback...")
|
||||||
|
final_state, signal = graph.propagate(
|
||||||
|
company_name="AAPL",
|
||||||
|
trade_date="2024-01-01",
|
||||||
|
on_step_callback=debug_callback
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"✅ Propagation completed!")
|
||||||
|
print(f"📈 Final signal: {signal}")
|
||||||
|
print(f"🎯 Final state keys: {list(final_state.keys())}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Error during streaming test: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_streaming()
|
||||||
|
|
@ -0,0 +1,159 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
SSL Certificate Diagnostic Tool for TradingAgents
|
||||||
|
|
||||||
|
This script helps diagnose SSL/TLS certificate issues and provides guidance
|
||||||
|
on how to configure certificate bundles properly.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import ssl
|
||||||
|
import socket
|
||||||
|
import requests
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv()
|
||||||
|
from tradingagents.dataflows.ssl_utils import get_certificate_info, get_ssl_config
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
|
||||||
|
def test_ssl_connection(hostname, port=443):
|
||||||
|
"""Test SSL connection to a specific hostname."""
|
||||||
|
print(f"\n🔒 Testing SSL connection to {hostname}:{port}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Create SSL context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
|
# Connect and get certificate info
|
||||||
|
with socket.create_connection((hostname, port), timeout=10) as sock:
|
||||||
|
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
|
||||||
|
cert = ssock.getpeercert()
|
||||||
|
print(f"✅ SSL connection successful")
|
||||||
|
print(f" Subject: {cert.get('subject', 'Unknown')}")
|
||||||
|
print(f" Issuer: {cert.get('issuer', 'Unknown')}")
|
||||||
|
print(f" Version: {cert.get('version', 'Unknown')}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ SSL connection failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def test_requests_connection(url):
|
||||||
|
"""Test HTTP request with requests library."""
|
||||||
|
print(f"\n🌐 Testing HTTP request to {url}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url, timeout=10)
|
||||||
|
print(f"✅ HTTP request successful")
|
||||||
|
print(f" Status: {response.status_code}")
|
||||||
|
print(f" SSL Cert: {response.raw.connection.sock.getpeercert().get('subject', 'Unknown') if hasattr(response.raw.connection, 'sock') else 'Unknown'}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except requests.exceptions.SSLError as e:
|
||||||
|
print(f"❌ SSL Error: {e}")
|
||||||
|
return False
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Request failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def test_with_custom_cert_bundle(url, cert_bundle_path):
|
||||||
|
"""Test HTTP request with custom certificate bundle."""
|
||||||
|
print(f"\n🔐 Testing with custom cert bundle: {cert_bundle_path}")
|
||||||
|
|
||||||
|
if not os.path.exists(cert_bundle_path):
|
||||||
|
print(f"❌ Certificate bundle not found: {cert_bundle_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.get(url, verify=cert_bundle_path, timeout=10)
|
||||||
|
print(f"✅ Request with custom cert bundle successful")
|
||||||
|
print(f" Status: {response.status_code}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"❌ Request with custom cert bundle failed: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main diagnostic function."""
|
||||||
|
print("🔍 TradingAgents SSL Certificate Diagnostic Tool")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Get certificate information
|
||||||
|
print("\n📋 Certificate Bundle Information:")
|
||||||
|
cert_info = get_certificate_info()
|
||||||
|
for key, value in cert_info.items():
|
||||||
|
if isinstance(value, list):
|
||||||
|
print(f" {key}: {', '.join(value) if value else 'None found'}")
|
||||||
|
else:
|
||||||
|
print(f" {key}: {value}")
|
||||||
|
|
||||||
|
# Test SSL configuration
|
||||||
|
print(f"\n⚙️ Current SSL Configuration:")
|
||||||
|
ssl_config = get_ssl_config(DEFAULT_CONFIG)
|
||||||
|
for key, value in ssl_config.items():
|
||||||
|
print(f" {key}: {value}")
|
||||||
|
|
||||||
|
# Test common endpoints
|
||||||
|
test_endpoints = [
|
||||||
|
("api.openai.com", 443),
|
||||||
|
("openrouter.ai", 443),
|
||||||
|
("generativelanguage.googleapis.com", 443),
|
||||||
|
("www.google.com", 443)
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🎯 Testing SSL connections:")
|
||||||
|
for hostname, port in test_endpoints:
|
||||||
|
test_ssl_connection(hostname, port)
|
||||||
|
|
||||||
|
# Test HTTP requests
|
||||||
|
test_urls = [
|
||||||
|
"https://api.openai.com/v1/models",
|
||||||
|
"https://www.google.com/search?q=test",
|
||||||
|
"https://openrouter.ai/api/v1/models"
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🌍 Testing HTTP requests:")
|
||||||
|
for url in test_urls:
|
||||||
|
test_requests_connection(url)
|
||||||
|
|
||||||
|
# Test with different certificate bundles
|
||||||
|
if cert_info.get("certifi_bundle") and cert_info["certifi_bundle"] != "Not available (certifi not installed)":
|
||||||
|
print(f"\n🧪 Testing with certifi bundle:")
|
||||||
|
test_with_custom_cert_bundle("https://www.google.com", cert_info["certifi_bundle"])
|
||||||
|
|
||||||
|
# Provide recommendations
|
||||||
|
print(f"\n💡 Recommendations:")
|
||||||
|
print(" 📋 Certificate Bundle Configuration:")
|
||||||
|
print(" • Only set if you need a custom certificate bundle")
|
||||||
|
print(" • If not set, system default SSL behavior is used")
|
||||||
|
print(" export REQUESTS_CA_BUNDLE=/path/to/your/ca-bundle.crt")
|
||||||
|
print(" export CURL_CA_BUNDLE=/path/to/your/ca-bundle.crt")
|
||||||
|
|
||||||
|
print("\n ⚠️ SSL Verification (use with caution):")
|
||||||
|
print(" • Only disable for development/testing")
|
||||||
|
print(" • If not set, SSL verification is enabled by default")
|
||||||
|
print(" export SSL_VERIFY=false")
|
||||||
|
|
||||||
|
print("\n ⏱️ Timeout Configuration:")
|
||||||
|
print(" • Only set if default timeout is insufficient")
|
||||||
|
print(" export HTTP_TIMEOUT=60")
|
||||||
|
|
||||||
|
print("\n 🌐 Proxy Configuration:")
|
||||||
|
print(" • Only required if behind corporate firewall")
|
||||||
|
print(" export HTTP_PROXY=http://proxy.company.com:8080")
|
||||||
|
print(" export HTTPS_PROXY=https://proxy.company.com:8080")
|
||||||
|
|
||||||
|
print("\n 📝 Configuration:")
|
||||||
|
print(" • Add these to your .env file or export in shell")
|
||||||
|
print(" • Leave unset to use system defaults")
|
||||||
|
print(" • Only configure what you actually need")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test SSL configuration behavior
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
from tradingagents.dataflows.ssl_utils import get_ssl_config, setup_global_ssl_config
|
||||||
|
|
||||||
|
def test_ssl_config():
|
||||||
|
"""Test SSL configuration with different environment variable settings"""
|
||||||
|
|
||||||
|
print("🧪 Testing SSL Configuration Behavior")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Test 1: No environment variables set
|
||||||
|
print("\n1️⃣ Test: No SSL environment variables set")
|
||||||
|
os.environ.pop("REQUESTS_CA_BUNDLE", None)
|
||||||
|
os.environ.pop("CURL_CA_BUNDLE", None)
|
||||||
|
os.environ.pop("SSL_VERIFY", None)
|
||||||
|
os.environ.pop("HTTP_TIMEOUT", None)
|
||||||
|
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
print(f" Expected: Empty or minimal config (default behavior)")
|
||||||
|
|
||||||
|
# Test 2: Custom certificate bundle set
|
||||||
|
print("\n2️⃣ Test: Custom certificate bundle set")
|
||||||
|
os.environ["REQUESTS_CA_BUNDLE"] = "/custom/path/ca-bundle.crt"
|
||||||
|
|
||||||
|
# Re-import to get updated config
|
||||||
|
from importlib import reload
|
||||||
|
import tradingagents.default_config
|
||||||
|
reload(tradingagents.default_config)
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" Config ssl_cert_bundle: {config.get('ssl_cert_bundle')}")
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
print(f" Expected: cert_bundle and verify set to custom path")
|
||||||
|
|
||||||
|
# Test 3: SSL verification disabled
|
||||||
|
print("\n3️⃣ Test: SSL verification disabled")
|
||||||
|
os.environ.pop("REQUESTS_CA_BUNDLE", None)
|
||||||
|
os.environ["SSL_VERIFY"] = "false"
|
||||||
|
|
||||||
|
reload(tradingagents.default_config)
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" Config ssl_verify: {config.get('ssl_verify')}")
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
print(f" Expected: verify set to False")
|
||||||
|
|
||||||
|
# Test 4: Timeout and proxy settings
|
||||||
|
print("\n4️⃣ Test: Timeout and proxy settings")
|
||||||
|
os.environ["HTTP_TIMEOUT"] = "60"
|
||||||
|
os.environ["HTTP_PROXY"] = "http://proxy.example.com:8080"
|
||||||
|
os.environ["HTTPS_PROXY"] = "https://proxy.example.com:8080"
|
||||||
|
|
||||||
|
reload(tradingagents.default_config)
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" Config timeout: {config.get('http_timeout')}")
|
||||||
|
print(f" Config proxies: HTTP={config.get('http_proxy')}, HTTPS={config.get('https_proxy')}")
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
print(f" Expected: timeout and proxies in ssl_config")
|
||||||
|
|
||||||
|
# Test 5: Empty environment variables (should not be used)
|
||||||
|
print("\n5️⃣ Test: Empty environment variables")
|
||||||
|
os.environ["REQUESTS_CA_BUNDLE"] = ""
|
||||||
|
os.environ["HTTP_TIMEOUT"] = ""
|
||||||
|
|
||||||
|
reload(tradingagents.default_config)
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" Config ssl_cert_bundle: '{config.get('ssl_cert_bundle')}'")
|
||||||
|
print(f" Config http_timeout: {config.get('http_timeout')}")
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
print(f" Expected: Empty values should not be used")
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
for var in ["REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_VERIFY", "HTTP_TIMEOUT", "HTTP_PROXY", "HTTPS_PROXY"]:
|
||||||
|
os.environ.pop(var, None)
|
||||||
|
|
||||||
|
print("\n✅ SSL configuration tests completed")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_ssl_config()
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test SSL connectivity for TradingAgents components
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
# Load environment variables
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
def test_api_connections():
|
||||||
|
"""Test API connections that TradingAgents will use"""
|
||||||
|
|
||||||
|
print("🔍 Testing TradingAgents API Connections")
|
||||||
|
print("=" * 50)
|
||||||
|
|
||||||
|
# Test 1: Basic HTTP requests with proper SSL
|
||||||
|
print("\n1️⃣ Testing HTTP requests with SSL configuration:")
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
test_endpoints = [
|
||||||
|
("OpenAI API", "https://api.openai.com/v1/models"),
|
||||||
|
("Google Search", "https://www.google.com/search?q=AAPL"),
|
||||||
|
("OpenRouter API", "https://openrouter.ai/api/v1/models"),
|
||||||
|
]
|
||||||
|
|
||||||
|
for name, url in test_endpoints:
|
||||||
|
try:
|
||||||
|
response = requests.get(url, timeout=10)
|
||||||
|
print(f" ✅ {name}: Status {response.status_code}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ {name}: {e}")
|
||||||
|
|
||||||
|
# Test 2: LangChain LLM initialization
|
||||||
|
print("\n2️⃣ Testing LangChain LLM initialization:")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
|
||||||
|
# Test with the SSL configuration
|
||||||
|
llm = ChatOpenAI(
|
||||||
|
model="gpt-3.5-turbo",
|
||||||
|
api_key=os.getenv("OPENAI_API_KEY", "test-key")
|
||||||
|
)
|
||||||
|
print(" ✅ ChatOpenAI initialization successful")
|
||||||
|
|
||||||
|
# Test a simple API call (this might fail due to API key, but SSL should work)
|
||||||
|
try:
|
||||||
|
# This will test SSL connectivity
|
||||||
|
response = llm.invoke("Hello")
|
||||||
|
print(" ✅ ChatOpenAI API call successful")
|
||||||
|
except Exception as e:
|
||||||
|
if "401" in str(e) or "Unauthorized" in str(e):
|
||||||
|
print(" ✅ ChatOpenAI SSL working (401 = API key issue, not SSL)")
|
||||||
|
else:
|
||||||
|
print(f" ⚠️ ChatOpenAI API call error: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ ChatOpenAI initialization failed: {e}")
|
||||||
|
|
||||||
|
# Test 3: TradingAgents configuration
|
||||||
|
print("\n3️⃣ Testing TradingAgents SSL configuration:")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
from tradingagents.dataflows.ssl_utils import get_ssl_config, setup_global_ssl_config
|
||||||
|
|
||||||
|
print(f" 📋 SSL cert bundle: {DEFAULT_CONFIG.get('ssl_cert_bundle')}")
|
||||||
|
print(f" 📋 SSL verify: {DEFAULT_CONFIG.get('ssl_verify')}")
|
||||||
|
|
||||||
|
ssl_config = get_ssl_config(DEFAULT_CONFIG)
|
||||||
|
print(f" 📋 SSL config: {ssl_config}")
|
||||||
|
|
||||||
|
# Set up global SSL configuration
|
||||||
|
setup_global_ssl_config(DEFAULT_CONFIG)
|
||||||
|
print(" ✅ Global SSL configuration applied")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ TradingAgents SSL configuration failed: {e}")
|
||||||
|
|
||||||
|
# Test 4: Google News functionality
|
||||||
|
print("\n4️⃣ Testing Google News data retrieval:")
|
||||||
|
|
||||||
|
try:
|
||||||
|
from tradingagents.dataflows.googlenews_utils import getNewsData
|
||||||
|
from tradingagents.dataflows.ssl_utils import get_ssl_config
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
|
||||||
|
ssl_config = get_ssl_config(DEFAULT_CONFIG)
|
||||||
|
|
||||||
|
# Test news retrieval with SSL config
|
||||||
|
news_results = getNewsData("AAPL", "2024-01-01", "2024-01-02", ssl_config)
|
||||||
|
print(f" ✅ Google News retrieval successful, got {len(news_results)} results")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ Google News retrieval failed: {e}")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_api_connections()
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Test TradingAgents SSL connections specifically
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Add project root to path
|
||||||
|
project_root = Path(__file__).parent.absolute()
|
||||||
|
if str(project_root) not in sys.path:
|
||||||
|
sys.path.insert(0, str(project_root))
|
||||||
|
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
from tradingagents.default_config import DEFAULT_CONFIG
|
||||||
|
from tradingagents.dataflows.ssl_utils import get_ssl_config, setup_global_ssl_config, get_certificate_info
|
||||||
|
from tradingagents.graph.trading_graph import TradingAgentsGraph
|
||||||
|
import requests
|
||||||
|
|
||||||
|
def test_certificate_issues():
|
||||||
|
"""Test SSL certificate issues that might occur in TradingAgents"""
|
||||||
|
|
||||||
|
print("🔍 Testing TradingAgents SSL Certificate Issues")
|
||||||
|
print("=" * 55)
|
||||||
|
|
||||||
|
# Show environment variables
|
||||||
|
print("\n📋 Environment Variables:")
|
||||||
|
ssl_vars = ["REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_VERIFY", "HTTP_TIMEOUT",
|
||||||
|
"HTTP_PROXY", "HTTPS_PROXY", "OPENAI_API_KEY", "FINNHUB_API_KEY"]
|
||||||
|
for var in ssl_vars:
|
||||||
|
value = os.getenv(var)
|
||||||
|
if value:
|
||||||
|
if "API_KEY" in var:
|
||||||
|
print(f" {var}: {'*' * min(8, len(value))}...")
|
||||||
|
else:
|
||||||
|
print(f" {var}: {value}")
|
||||||
|
else:
|
||||||
|
print(f" {var}: Not set")
|
||||||
|
|
||||||
|
# Show certificate info
|
||||||
|
print("\n📋 Certificate Bundle Information:")
|
||||||
|
cert_info = get_certificate_info()
|
||||||
|
for key, value in cert_info.items():
|
||||||
|
if isinstance(value, list):
|
||||||
|
print(f" {key}: {', '.join(value) if value else 'None found'}")
|
||||||
|
else:
|
||||||
|
print(f" {key}: {value}")
|
||||||
|
|
||||||
|
# Test SSL config
|
||||||
|
print("\n⚙️ Current SSL Configuration:")
|
||||||
|
config = DEFAULT_CONFIG.copy()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
print(f" SSL Config: {ssl_config}")
|
||||||
|
|
||||||
|
# Set up global SSL config
|
||||||
|
print("\n🔧 Setting up global SSL configuration...")
|
||||||
|
setup_global_ssl_config(config)
|
||||||
|
|
||||||
|
# Test basic HTTPS connections
|
||||||
|
test_urls = [
|
||||||
|
"https://api.openai.com/",
|
||||||
|
"https://www.google.com/",
|
||||||
|
"https://openrouter.ai/",
|
||||||
|
"https://finnhub.io/"
|
||||||
|
]
|
||||||
|
|
||||||
|
print(f"\n🌐 Testing HTTPS connections:")
|
||||||
|
for url in test_urls:
|
||||||
|
try:
|
||||||
|
print(f" Testing {url}...")
|
||||||
|
response = requests.get(url, timeout=10)
|
||||||
|
print(f" ✅ {url}: Status {response.status_code}")
|
||||||
|
except requests.exceptions.SSLError as e:
|
||||||
|
print(f" ❌ SSL Error for {url}: {e}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ Connection error for {url}: {e}")
|
||||||
|
|
||||||
|
# Test TradingAgentsGraph initialization
|
||||||
|
print(f"\n🤖 Testing TradingAgentsGraph initialization:")
|
||||||
|
try:
|
||||||
|
# Create minimal config
|
||||||
|
test_config = DEFAULT_CONFIG.copy()
|
||||||
|
test_config["llm_provider"] = "openai"
|
||||||
|
test_config["quick_think_llm"] = "gpt-3.5-turbo"
|
||||||
|
test_config["deep_think_llm"] = "gpt-4"
|
||||||
|
|
||||||
|
print(" Creating TradingAgentsGraph...")
|
||||||
|
graph = TradingAgentsGraph(config=test_config)
|
||||||
|
print(" ✅ TradingAgentsGraph created successfully")
|
||||||
|
|
||||||
|
# Test if we can make a simple LLM call
|
||||||
|
print(" Testing LLM connection...")
|
||||||
|
try:
|
||||||
|
# This won't actually make an API call but will test the LLM initialization
|
||||||
|
llm = graph.quick_thinking_llm
|
||||||
|
print(f" ✅ LLM initialized: {llm}")
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ LLM initialization error: {e}")
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f" ❌ TradingAgentsGraph initialization error: {e}")
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# Recommendations based on findings
|
||||||
|
print(f"\n💡 Troubleshooting Recommendations:")
|
||||||
|
|
||||||
|
# Check if we're on macOS and suggest system certificates
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
macos_cert = "/etc/ssl/cert.pem"
|
||||||
|
if os.path.exists(macos_cert):
|
||||||
|
print(f" 📱 macOS detected - try: export REQUESTS_CA_BUNDLE={macos_cert}")
|
||||||
|
else:
|
||||||
|
print(f" 📱 macOS detected but {macos_cert} not found")
|
||||||
|
|
||||||
|
# Check for certifi
|
||||||
|
try:
|
||||||
|
import certifi
|
||||||
|
print(f" 🔐 Certifi available - try: export REQUESTS_CA_BUNDLE={certifi.where()}")
|
||||||
|
except ImportError:
|
||||||
|
print(f" ❌ Certifi not installed - try: pip install certifi")
|
||||||
|
|
||||||
|
# Corporate environment suggestions
|
||||||
|
print(f" 🏢 If behind corporate firewall:")
|
||||||
|
print(f" • Contact IT for corporate certificate bundle")
|
||||||
|
print(f" • Check if HTTP_PROXY/HTTPS_PROXY needed")
|
||||||
|
print(f" • Ask about custom CA certificates")
|
||||||
|
|
||||||
|
# Temporary workaround (not recommended for production)
|
||||||
|
print(f" 🚨 Temporary workaround (development only):")
|
||||||
|
print(f" export SSL_VERIFY=false")
|
||||||
|
print(f" ⚠️ This disables SSL verification - use with caution!")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_certificate_issues()
|
||||||
|
|
@ -23,20 +23,36 @@ def is_rate_limited(response):
|
||||||
wait=wait_exponential(multiplier=1, min=4, max=60),
|
wait=wait_exponential(multiplier=1, min=4, max=60),
|
||||||
stop=stop_after_attempt(5),
|
stop=stop_after_attempt(5),
|
||||||
)
|
)
|
||||||
def make_request(url, headers):
|
def make_request(url, headers, ssl_config=None):
|
||||||
"""Make a request with retry logic for rate limiting"""
|
"""Make a request with retry logic for rate limiting"""
|
||||||
# Random delay before each request to avoid detection
|
# Random delay before each request to avoid detection
|
||||||
time.sleep(random.uniform(2, 6))
|
time.sleep(random.uniform(2, 6))
|
||||||
response = requests.get(url, headers=headers)
|
|
||||||
|
# Prepare SSL configuration - only use if explicitly configured
|
||||||
|
kwargs = {}
|
||||||
|
if ssl_config:
|
||||||
|
if ssl_config.get("cert_bundle"):
|
||||||
|
kwargs["verify"] = ssl_config["cert_bundle"]
|
||||||
|
elif "verify" in ssl_config:
|
||||||
|
kwargs["verify"] = ssl_config["verify"]
|
||||||
|
|
||||||
|
if ssl_config.get("timeout"):
|
||||||
|
kwargs["timeout"] = ssl_config["timeout"]
|
||||||
|
|
||||||
|
if ssl_config.get("proxies"):
|
||||||
|
kwargs["proxies"] = ssl_config["proxies"]
|
||||||
|
|
||||||
|
response = requests.get(url, headers=headers, **kwargs)
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
def getNewsData(query, start_date, end_date):
|
def getNewsData(query, start_date, end_date, ssl_config=None):
|
||||||
"""
|
"""
|
||||||
Scrape Google News search results for a given query and date range.
|
Scrape Google News search results for a given query and date range.
|
||||||
query: str - search query
|
query: str - search query
|
||||||
start_date: str - start date in the format yyyy-mm-dd or mm/dd/yyyy
|
start_date: str - start date in the format yyyy-mm-dd or mm/dd/yyyy
|
||||||
end_date: str - end date in the format yyyy-mm-dd or mm/dd/yyyy
|
end_date: str - end date in the format yyyy-mm-dd or mm/dd/yyyy
|
||||||
|
ssl_config: dict - SSL configuration including cert_bundle, verify, timeout, proxies
|
||||||
"""
|
"""
|
||||||
if "-" in start_date:
|
if "-" in start_date:
|
||||||
start_date = datetime.strptime(start_date, "%Y-%m-%d")
|
start_date = datetime.strptime(start_date, "%Y-%m-%d")
|
||||||
|
|
@ -64,7 +80,7 @@ def getNewsData(query, start_date, end_date):
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response = make_request(url, headers)
|
response = make_request(url, headers, ssl_config)
|
||||||
soup = BeautifulSoup(response.content, "html.parser")
|
soup = BeautifulSoup(response.content, "html.parser")
|
||||||
results_on_page = soup.select("div.SoaBEf")
|
results_on_page = soup.select("div.SoaBEf")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from .yfin_utils import *
|
||||||
from .stockstats_utils import *
|
from .stockstats_utils import *
|
||||||
from .googlenews_utils import *
|
from .googlenews_utils import *
|
||||||
from .finnhub_utils import get_data_in_range
|
from .finnhub_utils import get_data_in_range
|
||||||
|
from .ssl_utils import get_ssl_config, setup_global_ssl_config
|
||||||
from dateutil.relativedelta import relativedelta
|
from dateutil.relativedelta import relativedelta
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -294,7 +295,13 @@ def get_google_news(
|
||||||
before = start_date - relativedelta(days=look_back_days)
|
before = start_date - relativedelta(days=look_back_days)
|
||||||
before = before.strftime("%Y-%m-%d")
|
before = before.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
news_results = getNewsData(query, before, curr_date)
|
config = get_config()
|
||||||
|
ssl_config = get_ssl_config(config)
|
||||||
|
# Only pass ssl_config if it has actual configuration
|
||||||
|
if ssl_config:
|
||||||
|
news_results = getNewsData(query, before, curr_date, ssl_config)
|
||||||
|
else:
|
||||||
|
news_results = getNewsData(query, before, curr_date)
|
||||||
|
|
||||||
news_str = ""
|
news_str = ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,149 @@
|
||||||
|
"""
|
||||||
|
SSL/TLS configuration utilities for TradingAgents
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import ssl
|
||||||
|
import certifi
|
||||||
|
from typing import Dict, Any, Optional
|
||||||
|
|
||||||
|
|
||||||
|
def get_ssl_config(config: Dict[str, Any]) -> Dict[str, Any]:
|
||||||
|
"""
|
||||||
|
Create SSL configuration dictionary from the main config.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: Main configuration dictionary
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
SSL configuration dictionary with cert_bundle, verify, timeout, proxies
|
||||||
|
"""
|
||||||
|
ssl_config = {}
|
||||||
|
|
||||||
|
# Certificate bundle configuration - only use if explicitly specified
|
||||||
|
cert_bundle = config.get("ssl_cert_bundle")
|
||||||
|
if cert_bundle and cert_bundle.strip():
|
||||||
|
# Use explicitly specified certificate bundle
|
||||||
|
ssl_config["cert_bundle"] = cert_bundle
|
||||||
|
ssl_config["verify"] = cert_bundle
|
||||||
|
elif not config.get("ssl_verify", True):
|
||||||
|
# Only disable SSL verification if explicitly set to false
|
||||||
|
ssl_config["verify"] = False
|
||||||
|
|
||||||
|
# If no explicit cert bundle and ssl_verify is true (default),
|
||||||
|
# don't set anything - use default behavior
|
||||||
|
|
||||||
|
# Timeout configuration
|
||||||
|
if config.get("http_timeout"):
|
||||||
|
ssl_config["timeout"] = config["http_timeout"]
|
||||||
|
|
||||||
|
# Proxy configuration
|
||||||
|
proxies = {}
|
||||||
|
if config.get("http_proxy"):
|
||||||
|
proxies["http"] = config["http_proxy"]
|
||||||
|
if config.get("https_proxy"):
|
||||||
|
proxies["https"] = config["https_proxy"]
|
||||||
|
if proxies:
|
||||||
|
ssl_config["proxies"] = proxies
|
||||||
|
|
||||||
|
return ssl_config
|
||||||
|
|
||||||
|
|
||||||
|
def setup_global_ssl_config(config: Dict[str, Any]) -> None:
|
||||||
|
"""
|
||||||
|
Set up global SSL configuration for the application.
|
||||||
|
This affects all SSL connections made by requests and other libraries.
|
||||||
|
Only sets configuration if explicitly specified in environment variables.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: Main configuration dictionary
|
||||||
|
"""
|
||||||
|
# Set environment variables for requests library only if explicitly configured
|
||||||
|
cert_bundle = config.get("ssl_cert_bundle")
|
||||||
|
if cert_bundle and cert_bundle.strip():
|
||||||
|
os.environ["REQUESTS_CA_BUNDLE"] = cert_bundle
|
||||||
|
os.environ["CURL_CA_BUNDLE"] = cert_bundle
|
||||||
|
print(f"🔒 Using custom SSL certificate bundle: {cert_bundle}")
|
||||||
|
|
||||||
|
# Set SSL verification for requests only if explicitly disabled
|
||||||
|
if not config.get("ssl_verify", True):
|
||||||
|
# Disable SSL warnings when verification is disabled
|
||||||
|
import urllib3
|
||||||
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
print("⚠️ SSL certificate verification disabled")
|
||||||
|
|
||||||
|
# Set proxy environment variables if specified
|
||||||
|
if config.get("http_proxy"):
|
||||||
|
os.environ["HTTP_PROXY"] = config["http_proxy"]
|
||||||
|
print(f"🌐 Using HTTP proxy: {config['http_proxy']}")
|
||||||
|
if config.get("https_proxy"):
|
||||||
|
os.environ["HTTPS_PROXY"] = config["https_proxy"]
|
||||||
|
print(f"🌐 Using HTTPS proxy: {config['https_proxy']}")
|
||||||
|
|
||||||
|
# Set timeout if specified
|
||||||
|
if config.get("http_timeout"):
|
||||||
|
print(f"⏱️ HTTP timeout set to: {config['http_timeout']} seconds")
|
||||||
|
|
||||||
|
|
||||||
|
def create_ssl_context(cert_bundle: Optional[str] = None, verify_ssl: bool = True) -> ssl.SSLContext:
|
||||||
|
"""
|
||||||
|
Create a custom SSL context with specified certificate bundle.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cert_bundle: Path to certificate bundle file
|
||||||
|
verify_ssl: Whether to verify SSL certificates
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Configured SSL context
|
||||||
|
"""
|
||||||
|
if not verify_ssl:
|
||||||
|
# Create unverified context (not recommended for production)
|
||||||
|
context = ssl._create_unverified_context()
|
||||||
|
else:
|
||||||
|
# Create default context
|
||||||
|
context = ssl.create_default_context()
|
||||||
|
|
||||||
|
if cert_bundle:
|
||||||
|
# Load custom certificate bundle
|
||||||
|
context.load_verify_locations(cafile=cert_bundle)
|
||||||
|
|
||||||
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
def get_certificate_info() -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Get information about available certificate bundles.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Dictionary with certificate bundle information
|
||||||
|
"""
|
||||||
|
info = {}
|
||||||
|
|
||||||
|
# Check certifi bundle
|
||||||
|
try:
|
||||||
|
import certifi
|
||||||
|
info["certifi_bundle"] = certifi.where()
|
||||||
|
except ImportError:
|
||||||
|
info["certifi_bundle"] = "Not available (certifi not installed)"
|
||||||
|
|
||||||
|
# Check environment variables
|
||||||
|
info["env_ca_bundle"] = os.getenv("REQUESTS_CA_BUNDLE", "Not set")
|
||||||
|
info["env_curl_bundle"] = os.getenv("CURL_CA_BUNDLE", "Not set")
|
||||||
|
|
||||||
|
# Check system certificate stores
|
||||||
|
common_cert_paths = [
|
||||||
|
"/etc/ssl/certs/ca-certificates.crt", # Debian/Ubuntu
|
||||||
|
"/etc/pki/tls/certs/ca-bundle.crt", # RedHat/CentOS
|
||||||
|
"/usr/local/share/certs/ca-root-nss.crt", # FreeBSD
|
||||||
|
"/etc/ssl/cert.pem", # OpenBSD
|
||||||
|
"/System/Library/OpenSSL/certs/cert.pem", # macOS
|
||||||
|
]
|
||||||
|
|
||||||
|
available_system_certs = []
|
||||||
|
for path in common_cert_paths:
|
||||||
|
if os.path.exists(path):
|
||||||
|
available_system_certs.append(path)
|
||||||
|
|
||||||
|
info["system_cert_bundles"] = available_system_certs
|
||||||
|
|
||||||
|
return info
|
||||||
|
|
@ -26,4 +26,11 @@ DEFAULT_CONFIG = {
|
||||||
"online_tools": True,
|
"online_tools": True,
|
||||||
"user_position": "none",
|
"user_position": "none",
|
||||||
"cost_per_trade": 0.0,
|
"cost_per_trade": 0.0,
|
||||||
|
# SSL/TLS Certificate settings - only use if explicitly set
|
||||||
|
"ssl_cert_bundle": os.getenv("REQUESTS_CA_BUNDLE") or os.getenv("CURL_CA_BUNDLE"),
|
||||||
|
"ssl_verify": os.getenv("SSL_VERIFY", "true").lower() in ("true", "1", "yes"),
|
||||||
|
"http_timeout": int(os.getenv("HTTP_TIMEOUT")) if os.getenv("HTTP_TIMEOUT") else None,
|
||||||
|
# Proxy settings (if needed)
|
||||||
|
"http_proxy": os.getenv("HTTP_PROXY"),
|
||||||
|
"https_proxy": os.getenv("HTTPS_PROXY"),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ from tradingagents.agents.utils.agent_states import (
|
||||||
RiskDebateState,
|
RiskDebateState,
|
||||||
)
|
)
|
||||||
from tradingagents.dataflows.interface import set_config
|
from tradingagents.dataflows.interface import set_config
|
||||||
|
from tradingagents.dataflows.ssl_utils import setup_global_ssl_config
|
||||||
|
|
||||||
from .conditional_logic import ConditionalLogic
|
from .conditional_logic import ConditionalLogic
|
||||||
from .setup import GraphSetup
|
from .setup import GraphSetup
|
||||||
|
|
@ -51,6 +52,9 @@ class TradingAgentsGraph:
|
||||||
# Update the interface's config
|
# Update the interface's config
|
||||||
set_config(self.config)
|
set_config(self.config)
|
||||||
|
|
||||||
|
# Set up global SSL configuration
|
||||||
|
setup_global_ssl_config(self.config)
|
||||||
|
|
||||||
# Create necessary directories
|
# Create necessary directories
|
||||||
os.makedirs(
|
os.makedirs(
|
||||||
os.path.join(self.config["project_dir"], "dataflows/data_cache"),
|
os.path.join(self.config["project_dir"], "dataflows/data_cache"),
|
||||||
|
|
@ -79,15 +83,48 @@ class TradingAgentsGraph:
|
||||||
"export OPENAI_API_KEY=your_openai_key_here"
|
"export OPENAI_API_KEY=your_openai_key_here"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Prepare SSL configuration for HTTP client - only if explicitly configured
|
||||||
|
http_client_kwargs = {}
|
||||||
|
cert_bundle = self.config.get("ssl_cert_bundle")
|
||||||
|
|
||||||
|
if cert_bundle and cert_bundle.strip():
|
||||||
|
import httpx
|
||||||
|
http_client_kwargs["verify"] = cert_bundle
|
||||||
|
elif not self.config.get("ssl_verify", True):
|
||||||
|
import httpx
|
||||||
|
http_client_kwargs["verify"] = False
|
||||||
|
|
||||||
|
if self.config.get("http_timeout"):
|
||||||
|
import httpx
|
||||||
|
http_client_kwargs["timeout"] = self.config["http_timeout"]
|
||||||
|
|
||||||
|
# Add proxy configuration if specified
|
||||||
|
if self.config.get("http_proxy") or self.config.get("https_proxy"):
|
||||||
|
import httpx
|
||||||
|
proxies = {}
|
||||||
|
if self.config.get("http_proxy"):
|
||||||
|
proxies["http://"] = self.config["http_proxy"]
|
||||||
|
if self.config.get("https_proxy"):
|
||||||
|
proxies["https://"] = self.config["https_proxy"]
|
||||||
|
http_client_kwargs["proxies"] = proxies
|
||||||
|
|
||||||
|
# Create HTTP client only if we have custom settings
|
||||||
|
http_client = None
|
||||||
|
if http_client_kwargs:
|
||||||
|
import httpx
|
||||||
|
http_client = httpx.Client(**http_client_kwargs)
|
||||||
|
|
||||||
self.deep_thinking_llm = ChatOpenAI(
|
self.deep_thinking_llm = ChatOpenAI(
|
||||||
model=self.config["deep_think_llm"],
|
model=self.config["deep_think_llm"],
|
||||||
base_url=self.config["backend_url"],
|
base_url=self.config["backend_url"],
|
||||||
api_key=api_key
|
api_key=api_key,
|
||||||
|
http_client=http_client
|
||||||
)
|
)
|
||||||
self.quick_thinking_llm = ChatOpenAI(
|
self.quick_thinking_llm = ChatOpenAI(
|
||||||
model=self.config["quick_think_llm"],
|
model=self.config["quick_think_llm"],
|
||||||
base_url=self.config["backend_url"],
|
base_url=self.config["backend_url"],
|
||||||
api_key=api_key
|
api_key=api_key,
|
||||||
|
http_client=http_client
|
||||||
)
|
)
|
||||||
elif self.config["llm_provider"].lower() == "anthropic":
|
elif self.config["llm_provider"].lower() == "anthropic":
|
||||||
self.deep_thinking_llm = ChatAnthropic(model=self.config["deep_think_llm"], base_url=self.config["backend_url"])
|
self.deep_thinking_llm = ChatAnthropic(model=self.config["deep_think_llm"], base_url=self.config["backend_url"])
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue