diff --git a/README.md b/README.md index 036550d..d99481c 100644 --- a/README.md +++ b/README.md @@ -123,10 +123,7 @@ agents/salesagent/ Copy `.env.example` to `.env` and set your API credentials: ```env -COGSOL_ENV=local -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ -COGSOL_ +COGSOL_ENV=development COGSOL_API_KEY=your-api-key # Optional: Azure AD B2C client credentials for JWT # If not provided, the Auth will be skipped @@ -670,10 +667,8 @@ from cogsol.content import BaseRetrieval, ReorderingStrategy | Variable | Required | Description | |----------|----------|-------------| -| `COGSOL_API_BASE` | Yes | Base URL for the CogSol Cognitive API | -| `COGSOL_CONTENT_API_BASE` | No | Base URL for the CogSol Content API (defaults to `COGSOL_API_BASE`) | | `COGSOL_API_KEY` | Yes | API Key authentication | -| `COGSOL_ENV` | No | Environment name (e.g., `local`, `production`) | +| `COGSOL_ENV` | No | Environment name (e.g., `local`, `development`, `production`) | | `COGSOL_AUTH_CLIENT_ID` | No | Client Id provided for adminitrators | | `COGSOL_AUTH_SECRET` | No | Auth Secret provided for adminitrators | diff --git a/cogsol/agents/__init__.py b/cogsol/agents/__init__.py index 0245c2d..60af733 100644 --- a/cogsol/agents/__init__.py +++ b/cogsol/agents/__init__.py @@ -13,6 +13,7 @@ from typing import Any from cogsol.core.api import CogSolAPIError, CogSolClient +from cogsol.core.constants import get_cognitive_api_base_url from cogsol.core.env import load_dotenv @@ -98,7 +99,7 @@ def run( project_path = Path.cwd() load_dotenv(project_path / ".env") - base_url = api_base or self._api_base or os.environ.get("COGSOL_API_BASE") + base_url = api_base or self._api_base or get_cognitive_api_base_url() if not base_url: raise CogSolAPIError("COGSOL_API_BASE is required to run agents.") token = api_key or self._api_key or os.environ.get("COGSOL_API_KEY") diff --git a/cogsol/content/__init__.py b/cogsol/content/__init__.py index 63d3985..595cb6c 100644 --- a/cogsol/content/__init__.py +++ b/cogsol/content/__init__.py @@ -15,6 +15,10 @@ from typing import Any from cogsol.core.api import CogSolAPIError, CogSolClient +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) from cogsol.core.env import load_dotenv @@ -286,10 +290,8 @@ def run( project_path = Path.cwd() load_dotenv(project_path / ".env") - content_base = ( - content_api_base or self._content_api_base or os.environ.get("COGSOL_CONTENT_API_BASE") - ) - base_url = api_base or self._api_base or os.environ.get("COGSOL_API_BASE") or content_base + content_base = content_api_base or self._content_api_base or get_content_api_base_url() + base_url = api_base or self._api_base or get_cognitive_api_base_url() or content_base if not content_base: raise CogSolAPIError("COGSOL_CONTENT_API_BASE is required to run retrievals.") token = api_key or self._api_key or os.environ.get("COGSOL_API_KEY") diff --git a/cogsol/core/api.py b/cogsol/core/api.py index 0dc2971..f8347e8 100644 --- a/cogsol/core/api.py +++ b/cogsol/core/api.py @@ -13,6 +13,11 @@ import msal from jwt import decode +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) + class CogSolAPIError(RuntimeError): pass @@ -73,9 +78,9 @@ def __init__( api_key: str | None = None, content_base_url: str | None = None, ) -> None: - self.base_url = base_url or os.environ.get("COGSOL_API_BASE") or "" + self.base_url = base_url or get_cognitive_api_base_url() self.api_key = api_key or os.environ.get("COGSOL_API_KEY") - self.content_base_url = content_base_url or os.environ.get("COGSOL_CONTENT_API_BASE") + self.content_base_url = content_base_url or get_content_api_base_url() self.bearer_token = None self.bearer_token_expires_at = None diff --git a/cogsol/core/constants.py b/cogsol/core/constants.py new file mode 100644 index 0000000..f73ea0c --- /dev/null +++ b/cogsol/core/constants.py @@ -0,0 +1,66 @@ +"""Shared constants and helpers for CogSol API base URLs.""" + +from __future__ import annotations + +import os +from typing import Final + +COGSOL_ENV_VAR: Final = "COGSOL_ENV" +COGSOL_API_BASE_VAR: Final = "COGSOL_API_BASE" +COGSOL_CONTENT_API_BASE_VAR: Final = "COGSOL_CONTENT_API_BASE" + +IMPLANTATION_COGNITIVE_API_URL: Final = "https://apis-imp.cogsol.ai/cognitive" +IMPLANTATION_CONTENT_API_URL: Final = "https://apis-imp.cogsol.ai/content" +PRODUCTION_COGNITIVE_API_URL: Final = "https://apis.cogsol.ai/cognitive" +PRODUCTION_CONTENT_API_URL: Final = "https://apis.cogsol.ai/content" + + +def _get_env_var(name: str) -> str | None: + """Return an environment variable value (case-insensitive).""" + return os.environ.get(name) or os.environ.get(name.lower()) + + +def get_cogsol_env() -> str: + """Return the current CogSol environment name.""" + value = _get_env_var(COGSOL_ENV_VAR) + return value.strip().lower() if value else "" + + +def get_default_cognitive_api_base_url() -> str: + """Return the default base URL for the cognitive API.""" + if get_cogsol_env() == "production": + return PRODUCTION_COGNITIVE_API_URL + return IMPLANTATION_COGNITIVE_API_URL + + +def get_default_content_api_base_url() -> str: + """Return the default base URL for the content API.""" + if get_cogsol_env() == "production": + return PRODUCTION_CONTENT_API_URL + return IMPLANTATION_CONTENT_API_URL + + +def get_cognitive_api_base_url() -> str: + """Resolve the cognitive API base URL using env overrides when present.""" + return _get_env_var(COGSOL_API_BASE_VAR) or get_default_cognitive_api_base_url() + + +def get_content_api_base_url() -> str: + """Resolve the content API base URL using env overrides when present.""" + return _get_env_var(COGSOL_CONTENT_API_BASE_VAR) or get_default_content_api_base_url() + + +__all__ = [ + "COGSOL_ENV_VAR", + "COGSOL_API_BASE_VAR", + "COGSOL_CONTENT_API_BASE_VAR", + "IMPLANTATION_COGNITIVE_API_URL", + "IMPLANTATION_CONTENT_API_URL", + "PRODUCTION_COGNITIVE_API_URL", + "PRODUCTION_CONTENT_API_URL", + "get_cogsol_env", + "get_default_cognitive_api_base_url", + "get_default_content_api_base_url", + "get_cognitive_api_base_url", + "get_content_api_base_url", +] diff --git a/cogsol/management/commands/chat.py b/cogsol/management/commands/chat.py index 9a368cb..6c3266c 100644 --- a/cogsol/management/commands/chat.py +++ b/cogsol/management/commands/chat.py @@ -10,6 +10,7 @@ from typing import Any, cast from cogsol.core.api import CogSolAPIError, CogSolClient +from cogsol.core.constants import get_cognitive_api_base_url from cogsol.core.env import load_dotenv from cogsol.management.base import BaseCommand @@ -316,7 +317,7 @@ def handle(self, project_path: Path | None, **options: Any) -> int: app = str(options.get("app") or "agents") load_dotenv(project_path / ".env") - api_base = os.environ.get("COGSOL_API_BASE") + api_base = get_cognitive_api_base_url() api_key = os.environ.get("COGSOL_API_KEY") if not api_base: print_error("COGSOL_API_BASE is required in .env to chat with CogSol.") diff --git a/cogsol/management/commands/importagent.py b/cogsol/management/commands/importagent.py index 414c01d..17c7736 100644 --- a/cogsol/management/commands/importagent.py +++ b/cogsol/management/commands/importagent.py @@ -6,6 +6,10 @@ from typing import Any, cast from cogsol.core.api import CogSolAPIError, CogSolClient +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) from cogsol.core.env import load_dotenv from cogsol.core.loader import ( _extract_tool_params, @@ -289,9 +293,9 @@ def handle(self, project_path: Path | None, **options: Any) -> int: import os - api_base = os.environ.get("COGSOL_API_BASE") + api_base = get_cognitive_api_base_url() api_key = os.environ.get("COGSOL_API_KEY") - content_base = os.environ.get("COGSOL_CONTENT_API_BASE") or api_base + content_base = get_content_api_base_url() or api_base if not api_base: print("COGSOL_API_BASE is required in .env to import.") return 1 diff --git a/cogsol/management/commands/ingest.py b/cogsol/management/commands/ingest.py index f77c6c4..2776020 100644 --- a/cogsol/management/commands/ingest.py +++ b/cogsol/management/commands/ingest.py @@ -12,6 +12,10 @@ from cogsol.content import BaseIngestionConfig, DocType from cogsol.core.api import CogSolClient +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) from cogsol.core.env import load_dotenv from cogsol.management.base import BaseCommand @@ -36,26 +40,11 @@ def get_client(project_path: Path) -> CogSolClient: """Get an API client configured for the project.""" - import sys - load_dotenv(project_path / ".env") - - sys.path.insert(0, str(project_path)) - try: - import settings - - api_base = getattr(settings, "COGSOL_API_BASE", None) - content_base = getattr(settings, "COGSOL_CONTENT_API_BASE", None) - except ImportError: - api_base = None - content_base = None - finally: - sys.path.pop(0) - import os - api_base = api_base or os.environ.get("COGSOL_API_BASE", "http://localhost:8000") - content_base = content_base or os.environ.get("COGSOL_CONTENT_API_BASE", api_base) + api_base = get_cognitive_api_base_url() + content_base = get_content_api_base_url() token = os.environ.get("COGSOL_API_KEY") return CogSolClient(base_url=api_base, api_key=token, content_base_url=content_base) diff --git a/cogsol/management/commands/migrate.py b/cogsol/management/commands/migrate.py index a876ce0..35763c0 100644 --- a/cogsol/management/commands/migrate.py +++ b/cogsol/management/commands/migrate.py @@ -4,6 +4,7 @@ import copy import inspect import json +import os import re import textwrap from pathlib import Path @@ -13,6 +14,10 @@ from cogsol.content import BaseRetrieval from cogsol.core import migrations as migutils from cogsol.core.api import CogSolAPIError, CogSolClient +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) from cogsol.core.env import load_dotenv from cogsol.core.loader import _extract_tool_params, collect_classes, collect_content_classes from cogsol.db import migrations @@ -59,9 +64,9 @@ def handle(self, project_path: Path | None, **options: Any) -> int: apps = [str(app)] if app else ["agents", "data"] load_dotenv(project_path / ".env") - api_base = self._env("COGSOL_API_BASE") + api_base = get_cognitive_api_base_url() api_key = self._env("COGSOL_API_KEY", required=False) - content_base = self._env("COGSOL_CONTENT_API_BASE", required=False) or api_base + content_base = get_content_api_base_url() if not api_base: print("COGSOL_API_BASE is required in .env to run migrations against CogSol APIs.") return 1 @@ -158,8 +163,6 @@ def handle(self, project_path: Path | None, **options: Any) -> int: # ------------------------------------------------------------------ helpers def _env(self, key: str, required: bool = True) -> str | None: - import os - value = os.environ.get(key) if required and not value: return None diff --git a/cogsol/management/commands/startproject.py b/cogsol/management/commands/startproject.py index 865315f..1a32adf 100644 --- a/cogsol/management/commands/startproject.py +++ b/cogsol/management/commands/startproject.py @@ -194,7 +194,7 @@ def handle(self, project_path: Path | None, **options: Any) -> int: "data/retrievals.py": DATA_RETRIEVALS_PY, "data/migrations/__init__.py": "", "README.md": README.format(project_name=name), - ".env.example": "COGSOL_ENV=local\nCOGSOL_API_BASE=http://localhost:8000\nCOGSOL_CONTENT_API_BASE=http://localhost:8001\n# Optional: COGSOL_API_KEY=your-api-key\n# Optional: Azure AD B2C client credentials for JWT\n# If not provided, the Auth will be skipped\n# COGSOL_AUTH_CLIENT_ID=you-client-id\n# COGSOL_AUTH_SECRET=your-secret\n", + ".env.example": "COGSOL_ENV=development\n#COGSOL_API_KEY=your-api-key\n# Optional: Azure AD B2C client credentials for JWT\n# If not provided, the Auth will be skipped\n# COGSOL_AUTH_CLIENT_ID=you-client-id\n# COGSOL_AUTH_SECRET=your-secret\n", } for relative_path, content in files.items(): diff --git a/cogsol/management/commands/topics.py b/cogsol/management/commands/topics.py index 87e3810..83f1a6e 100644 --- a/cogsol/management/commands/topics.py +++ b/cogsol/management/commands/topics.py @@ -6,32 +6,21 @@ from typing import Any from cogsol.core.api import CogSolClient +from cogsol.core.constants import ( + get_cognitive_api_base_url, + get_content_api_base_url, +) from cogsol.core.env import load_dotenv from cogsol.management.base import BaseCommand def get_client(project_path: Path) -> CogSolClient: """Get an API client configured for the project.""" - import sys - load_dotenv(project_path / ".env") - - sys.path.insert(0, str(project_path)) - try: - import settings - - api_base = getattr(settings, "COGSOL_API_BASE", None) - content_base = getattr(settings, "COGSOL_CONTENT_API_BASE", None) - except ImportError: - api_base = None - content_base = None - finally: - sys.path.pop(0) - import os - api_base = api_base or os.environ.get("COGSOL_API_BASE", "http://localhost:8000") - content_base = content_base or os.environ.get("COGSOL_CONTENT_API_BASE", api_base) + api_base = get_cognitive_api_base_url() + content_base = get_content_api_base_url() api_key = os.environ.get("COGSOL_API_KEY") return CogSolClient(base_url=api_base, api_key=api_key, content_base_url=content_base) diff --git a/docs/api.md b/docs/api.md index c1aaa3d..40e8584 100644 --- a/docs/api.md +++ b/docs/api.md @@ -51,7 +51,7 @@ class CogSolClient: | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `base_url` | `str` | Yes | Base URL for the Cognitive API (e.g., `https://api.cogsol.ai/cognitive/`) | +| `base_url` | `str` | Yes | Base URL for the Cognitive API (e.g., `https://apis-imp.cogsol.ai/cognitive`) | | `token` | `str` | No | API authentication token | | `content_base_url` | `str` | No | Base URL for Content API (defaults to `base_url` if not set) | @@ -61,13 +61,13 @@ class CogSolClient: from cogsol.core.api import CogSolClient # Without authentication -client = CogSolClient(base_url="https://api.cogsol.ai/cognitive/") +client = CogSolClient(base_url="https://apis-imp.cogsol.ai/cognitive") # With authentication and separate Content API client = CogSolClient( - base_url="https://api.cogsol.ai/cognitive/", + base_url="https://apis-imp.cogsol.ai/cognitive", token="sk-your-api-key", - content_base_url="https://api.cogsol.ai/content/" + content_base_url="https://apis-imp.cogsol.ai/content" ) ``` @@ -595,7 +595,7 @@ class CogSolAPIError(RuntimeError): ```python from cogsol.core.api import CogSolClient, CogSolAPIError -client = CogSolClient(base_url="https://api.cogsol.ai/cognitive/", token="...") +client = CogSolClient(base_url="https://apis-imp.cogsol.ai/cognitive", token="...") try: assistant = client.get_assistant(9999) @@ -939,7 +939,7 @@ from cogsol.core.api import CogSolClient # Initialize client client = CogSolClient( - base_url="https://api.cogsol.ai/cognitive/", + base_url="https://apis-imp.cogsol.ai/cognitive", token="sk-your-token" ) diff --git a/docs/commands.md b/docs/commands.md index 10da148..486554c 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -146,15 +146,7 @@ Contains commented examples of retrieval configurations. ##### `.env.example` -```env -COGSOL_ENV=local -COGSOL_API_BASE=http://localhost:8000 -COGSOL_CONTENT_API_BASE=http://localhost:8001 -# Optional: COGSOL_API_KEY=your-api-key -# Optional: Azure AD B2C client credentials for JWT -# COGSOL_AUTH_CLIENT_ID=your-client-id -# COGSOL_AUTH_SECRET=your-client-secret -``` +Stores configuration variables for CogSol credentials. #### Example Usage @@ -484,9 +476,7 @@ python manage.py migrate [app] #### Required Environment Variables ```env -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ # Required -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ # Required for data app -COGSOL_API_KEY=your-api-key # Optional, but recommended +COGSOL_API_KEY=your-api-key COGSOL_AUTH_CLIENT_ID=your-client-id COGSOL_AUTH_SECRET=your-client-secret ``` @@ -734,10 +724,10 @@ python manage.py importagent [app] #### Required Environment Variables ```env -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ # Required +COGSOL_API_BASE=https://apis-imp.cogsol.ai/cognitive # Required COGSOL_API_KEY=your-api-key # Optional -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ # Required if importing retrievals +COGSOL_CONTENT_API_BASE=https://apis-imp.cogsol.ai/content # Required if importing retrievals ``` #### What Gets Imported @@ -817,7 +807,7 @@ python manage.py chat --agent [app] #### Required Environment Variables ```env -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ # Required +COGSOL_API_BASE=https://apis-imp.cogsol.ai/cognitive # Required COGSOL_API_KEY=your-api-key # Optional ``` @@ -885,48 +875,6 @@ python manage.py chat --agent Support assistants --- -## Environment Configuration - -### `.env` File - -Create a `.env` file in your project root: - -```env -# Required for migrate and chat commands -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ - -# Optional: API authentication token -COGSOL_API_KEY=sk-your-api-key - -# Optional: Environment identifier -COGSOL_ENV=production -``` - -### Environment Loading - -The framework loads `.env` automatically using a minimal built-in loader (no external dependencies): - -```python -# cogsol/core/env.py -def load_dotenv(dotenv_path: Path) -> None: - """ - Minimal .env loader. - Supports KEY=VALUE lines, ignores blanks and comments. - """ -``` - -### Variable Reference - -| Variable | Required For | Description | -|----------|--------------|-------------| -| `COGSOL_API_BASE` | `migrate`, `chat`, `importagent` | Base URL for CogSol API | -| `COGSOL_CONTENT_API_BASE` | `migrate`, `ingest`, `topics`, `importagent` | Base URL for the Content API (defaults to `COGSOL_API_BASE`) | -| `COGSOL_API_KEY` | - | API authentication (via `x-api-key` header) | -| `COGSOL_ENV` | - | Environment name (informational) | - ---- - ## Exit Codes All commands return standard exit codes: @@ -966,7 +914,7 @@ python manage.py makemigrations Create or update your `.env` file: ```bash -echo "COGSOL_API_BASE=https://api.cogsol.ai/cognitive/" >> .env +echo "COGSOL_API_BASE=https://apis-imp.cogsol.ai/cognitive" >> .env ``` #### "Could not resolve agent" diff --git a/docs/getting-started.md b/docs/getting-started.md index 98ef069..06bf45b 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -87,9 +87,9 @@ Update `.env` with your CogSol API credentials: ```env COGSOL_ENV=development -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ COGSOL_API_KEY=your-api-key-here +# Optional: Azure AD B2C client credentials for JWT +# If not provided, the Auth will be skipped COGSOL_AUTH_CLIENT_ID=your-client-id COGSOL_AUTH_SECRET=your-client-secret ``` @@ -669,8 +669,6 @@ class Migration(migrations.Migration): Verify your `.env` file has valid credentials: ```env -COGSOL_API_BASE=https://api.cogsol.ai/cognitive/ -COGSOL_CONTENT_API_BASE=https://api.cogsol.ai/content/ COGSOL_API_KEY=sk-your-valid-api-key COGSOL_AUTH_CLIENT_ID=your-client-id COGSOL_AUTH_SECRET=your-client-secret diff --git a/pyproject.toml b/pyproject.toml index 456ad9f..d7e5778 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,6 +9,7 @@ requires-python = ">=3.9" dependencies = [ "msal>=1.27", "PyJWT>=2.8", + "typing-extensions>=4.0", ] keywords = ["ai", "agents", "llm", "framework", "assistant", "chatbot"] classifiers = [