diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..00fcc28 --- /dev/null +++ b/.env.example @@ -0,0 +1,22 @@ +# Copy this file to .env and fill in your own values. +# .env is gitignored, never commit real credentials. + +# Required +ANTHROPIC_API_KEY= +DOMAIN_NAME= + +# Optional, used by the Smithery MCP registry integration +SMITHERY_API_KEY= + +# Optional agent configuration +AGENT_ID= +PORT=6000 +TERMINAL_PORT=6010 +PUBLIC_URL= +API_URL= + +# Optional behavior toggles +IMPROVE_MESSAGES=true +UI_MODE=true +UI_CLIENT_URL= +LOG_DIR=conversation_logs diff --git a/.gitignore b/.gitignore index e254ce5..4db7e38 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,18 @@ .env +.venv/ +venv/ jinoos/ .DS_Store +__pycache__/ +*.pyc +nanda_adapter/__pycache__/ +nanda_adapter/core/__pycache__/ agents/__pycache__/ -conversation_logs/ agents/test.py -nanda_agent/__pycache__ +conversation_logs/ +logs_*/ # Build artifacts dist/ +build/ *.egg-info/ - -nanda_adapter/core/__pycache__ \ No newline at end of file diff --git a/README.md b/README.md index 7ca262a..26f9343 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,13 @@ pip install nanda-adapter ### 4. Set Your enviroment variables ANTHROPIC_API_KEY (For running your personal hosted agents, need API key and your own domain) -> export ANTHROPIC_API_KEY="your-api-key-here +Copy `.env.example` to `.env` and fill it in, or export the variables directly: -> export DOMAIN_NAME=" +> export ANTHROPIC_API_KEY="your-api-key-here" + +> export DOMAIN_NAME="" + +If you use the Smithery MCP registry, set `SMITHERY_API_KEY` too. ### 5. Run an example agent (langchain_pirate.py) > nohup python3 langchain_pirate.py > out.log 2>&1 & diff --git a/nanda_adapter/core/agent_bridge.py b/nanda_adapter/core/agent_bridge.py index 26361d6..d26b1d3 100644 --- a/nanda_adapter/core/agent_bridge.py +++ b/nanda_adapter/core/agent_bridge.py @@ -19,14 +19,21 @@ import sys sys.stdout.reconfigure(line_buffering=True) -# Set API key through environment variable or directly in the code -ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") or "your key" +ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") # Toggle for message improvement feature IMPROVE_MESSAGES = os.getenv("IMPROVE_MESSAGES", "true").lower() in ("true", "1", "yes", "y") -# Create Anthropic client with explicit API key -anthropic = Anthropic(api_key=ANTHROPIC_API_KEY) +_anthropic_client = None + +def _get_anthropic_client(): + global _anthropic_client + if _anthropic_client is None: + api_key = os.getenv("ANTHROPIC_API_KEY") + if not api_key: + raise RuntimeError("ANTHROPIC_API_KEY is not set (see .env.example)") + _anthropic_client = Anthropic(api_key=api_key) + return _anthropic_client # Get agent configuration from environment variables def get_agent_id(): @@ -58,7 +65,7 @@ def get_agent_id(): "default": "Improve the following message to make it more clear, compelling, and professional without changing the core content or adding fictional information. Keep the same overall meaning but enhance the phrasing and structure. Don't make it too verbose - keep it concise but impactful. Return only the improved message without explanations or introductions." } -SMITHERY_API_KEY = os.getenv("SMITHERY_API_KEY") or "bfcb8cec-9d56-4957-8156-bced0bfca532" +SMITHERY_API_KEY = os.getenv("SMITHERY_API_KEY") def get_registry_url(): """Get the registry URL from file or use default""" @@ -169,7 +176,7 @@ def call_claude(prompt: str, additional_context: str, conversation_id: str, curr agent_id = get_agent_id() print(f"Agent {agent_id}: Calling Claude with prompt: {full_prompt[:50]}...") - resp = anthropic.messages.create( + resp = _get_anthropic_client().messages.create( model="claude-3-5-sonnet-20241022", max_tokens=512, messages=[{"role":"user","content":full_prompt}], @@ -201,7 +208,7 @@ def call_claude_direct(message_text: str, system_prompt: str = None) -> Optional agent_id = get_agent_id() print(f"Agent {agent_id}: Calling Claude with prompt: {full_prompt[:50]}...") - resp = anthropic.messages.create( + resp = _get_anthropic_client().messages.create( model="claude-3-5-sonnet-20241022", max_tokens=512, messages=[{"role":"user","content":full_prompt}], @@ -409,10 +416,9 @@ def form_mcp_server_url(url: str, config: dict, registry_name: str) -> Optional[ """ try: if registry_name == "smithery": - print("🔑 Using SMITHERY_API_KEY: ", SMITHERY_API_KEY) smithery_api_key = SMITHERY_API_KEY if not smithery_api_key: - print("❌ SMITHERY_API_KEY not found in environment.") + print("SMITHERY_API_KEY not set") return None config_b64 = base64.b64encode(json.dumps(config).encode()) mcp_server_url = f"{url}?api_key={smithery_api_key}&config={config_b64}" diff --git a/nanda_adapter/core/mcp_utils.py b/nanda_adapter/core/mcp_utils.py index 6042c28..ccd952d 100644 --- a/nanda_adapter/core/mcp_utils.py +++ b/nanda_adapter/core/mcp_utils.py @@ -38,8 +38,10 @@ class MCPClient: def __init__(self): self.session = None self.exit_stack = AsyncExitStack() - ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") or "your-key" - self.anthropic = Anthropic(api_key=ANTHROPIC_API_KEY) + api_key = os.getenv("ANTHROPIC_API_KEY") + if not api_key: + raise RuntimeError("ANTHROPIC_API_KEY is not set (see .env.example)") + self.anthropic = Anthropic(api_key=api_key) async def connect_to_mcp_and_get_tools(self, mcp_server_url, transport_type="http"): """Connect to MCP server and return available tools diff --git a/nanda_adapter/core/nanda.py b/nanda_adapter/core/nanda.py index 9bc8dc7..2773a10 100644 --- a/nanda_adapter/core/nanda.py +++ b/nanda_adapter/core/nanda.py @@ -68,7 +68,6 @@ def start_server(self): api_url = os.getenv("API_URL") agent_id = os.getenv("AGENT_ID") - ANTHROPIC_API_KEY = os.getenv("ANTHROPIC_API_KEY") or "your key" AGENT_ID = os.getenv("AGENT_ID", "default") # Default to 'default' if not specified PORT = int(os.getenv("PORT", "6000")) TERMINAL_PORT = int(os.getenv("TERMINAL_PORT", "6010"))