diff --git a/agent-council/SKILL.md b/agent-council/SKILL.md index d92f938..e5ac421 100644 --- a/agent-council/SKILL.md +++ b/agent-council/SKILL.md @@ -148,6 +148,16 @@ python3 -m pip install -e /path/to/agent-council/ | `AGENT_COUNCIL_MODEL` | No | `openai/gpt-4o-mini` | Model string (`provider/model`) | | `AGENT_COUNCIL_BASE_URL` | No | Provider default | Custom API endpoint (OpenRouter, LiteLLM, etc.) | +You can set these as environment variables or create a `.env` file in the directory you run `agent-council` from: + +```bash +# .env file +AGENT_COUNCIL_API_KEY=sk-... +AGENT_COUNCIL_MODEL=openai/gpt-4o-mini +``` + +Environment variables take precedence over `.env` file values. + Model strings follow PydanticAI convention: `openai/gpt-4o-mini`, `anthropic/claude-sonnet-4-20250514`, `deepseek/deepseek-v4-flash`, `google/gemini-2.0-flash`. ## Output diff --git a/agent-council/agent_council/config.py b/agent-council/agent_council/config.py index 1aa369f..ebbd372 100644 --- a/agent-council/agent_council/config.py +++ b/agent-council/agent_council/config.py @@ -1,14 +1,49 @@ -"""Configuration — env var loading with sensible defaults.""" +"""Configuration — env var loading with sensible defaults and .env support.""" import os +from pathlib import Path + + +def _load_dotenv(path: Path | None = None) -> None: + """Load .env file using stdlib only. Looks for .env in cwd by default. + + Minimal implementation — no python-dotenv dependency. Handles: + KEY=value + KEY="quoted value" + # comments + export KEY=value (strips export prefix) + """ + dotenv_path = path or Path.cwd() / ".env" + if not dotenv_path.exists(): + return + + for line in dotenv_path.read_text().splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + if line.startswith("export "): + line = line[7:].strip() + if "=" not in line: + continue + key, _, value = line.partition("=") + key = key.strip() + value = value.strip().strip("\"'") + if key and key not in os.environ: + os.environ[key] = value def load_config() -> dict: - """Load configuration from environment variables. + """Load configuration from environment variables and .env files. + + Checks for a .env file in the current working directory first, + then falls back to environment variables. Env vars always take + precedence over .env values. Returns dict with keys: api_key, model, base_url. Raises ValueError if AGENT_COUNCIL_API_KEY is not set. """ + _load_dotenv() + api_key = os.environ.get("AGENT_COUNCIL_API_KEY") model = os.environ.get("AGENT_COUNCIL_MODEL", "openai/gpt-4o-mini") base_url = os.environ.get("AGENT_COUNCIL_BASE_URL") @@ -16,9 +51,12 @@ def load_config() -> dict: if not api_key: raise ValueError( "AGENT_COUNCIL_API_KEY is not set. " - "Set it to your LLM provider's API key:\n" + "Set it via environment variable or create a .env file:\n" " export AGENT_COUNCIL_API_KEY='sk-...'\n" - " export AGENT_COUNCIL_MODEL='openai/gpt-4o-mini' # or your model" + " export AGENT_COUNCIL_MODEL='openai/gpt-4o-mini' # or your model\n\n" + "Or create a .env file in the current directory:\n" + " AGENT_COUNCIL_API_KEY=sk-...\n" + " AGENT_COUNCIL_MODEL=openai/gpt-4o-mini" ) config = {