From a499e8743a007e9ab15d5e3b1ecd6dd461449618 Mon Sep 17 00:00:00 2001 From: Jean Silva Date: Sat, 28 Feb 2026 13:21:23 +0100 Subject: [PATCH 1/2] feat: 11 LLM Providers are now supported (covering 90%+ of the market): MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit │ Provider │ Type │ Default Model │ Anthropic │ Cloud │ claude-haiku-4-5-20251001 │ OpenAI │ Cloud │ gpt-4o-mini │ Azure OpenAI │ Cloud │ gpt-4o-mini │ Google GenAI │ Cloud │ gemini-2.0-flash-exp │ Google Vertex AI │ Cloud │ gemini-2.0-flash-exp │ Groq │ Cloud │ llama-3.3-70b-versatile │ Mistral AI │ Cloud │ mistral-large-latest │ Cohere │ Cloud │ command-r-plus │ AWS Bedrock │ Cloud │ anthropic.claude-3-5-sonnet-20241022-v2:0 │ Ollama │ Local │ llama3.2 │ Hugging Face │ Cloud │ meta-llama/Llama-3.2-3B-Instruct Closes issue #16 --- README.md | 70 +- agentic-framework/pyproject.toml | 5 + .../src/agentic_framework/constants.py | 190 +++- .../agentic_framework/core/langgraph_agent.py | 20 +- .../agentic_framework/core/simple_agent.py | 20 +- agentic-framework/tests/test_constants.py | 928 ++++++++++++++++++ agentic-framework/tests/test_core_agents.py | 4 +- .../tests/test_developer_agent.py | 10 +- .../tests/test_github_pr_reviewer_agent.py | 8 +- .../tests/test_travel_coordinator_agent.py | 4 +- agentic-framework/uv.lock | 296 +++++- 11 files changed, 1481 insertions(+), 74 deletions(-) create mode 100644 agentic-framework/tests/test_constants.py diff --git a/README.md b/README.md index 7bd5061..d118854 100644 --- a/README.md +++ b/README.md @@ -105,20 +105,63 @@ Instead of spending days wiring together LLMs, tools, and execution environments --- +### 🧠 Supported LLM Providers + +The framework supports **10+ LLM providers** out of the box, covering 90%+ of the LLM market: + +| Provider | Type | Use Case | +|----------|-------|----------| +| **Anthropic** | Cloud | State-of-the-art reasoning (Claude) | +| **OpenAI** | Cloud | GPT-4, GPT-4.1, o1 series | +| **Azure OpenAI** | Cloud | Enterprise OpenAI deployments | +| **Google GenAI** | Cloud | Gemini models via API | +| **Google Vertex AI** | Cloud | Gemini models via GCP | +| **Groq** | Cloud | Ultra-fast inference | +| **Mistral AI** | Cloud | European privacy-focused models | +| **Cohere** | Cloud | Enterprise RAG and Command models | +| **AWS Bedrock** | Cloud | Anthropic, Titan, Meta via AWS | +| **Ollama** | Local | Run LLMs locally (zero API cost) | +| **Hugging Face** | Cloud | Open models from Hugging Face Hub | + +**Provider Priority:** Anthropic > Google Vertex > Google GenAI > Azure > Groq > Mistral > Cohere > Bedrock > HuggingFace > Ollama > OpenAI (fallback) + +--- + ## 🚀 Quick Start (Zero to Agent in 60s) ### 1. Add your Brain (API Key) -You need an **LLM API key** (OpenAI or Anthropic) to breathe life into your agents. The framework uses Langchain under the hood, so standard environment functions perfectly! +You need an **LLM API key** to breathe life into your agents. The framework supports 10+ LLM providers via LangChain! ```bash # Copy the template cp .env.example .env # Edit .env and paste your API key +# Choose one of the following providers: # OPENAI_API_KEY=sk-your-key-here # ANTHROPIC_API_KEY=sk-ant-your-key-here +# GOOGLE_API_KEY=your-google-key +# GROQ_API_KEY=gsk-your-key-here +# MISTRAL_API_KEY=your-mistral-key-here +# COHERE_API_KEY=your-cohere-key-here + +# For Ollama (local), no API key needed: +# OLLAMA_BASE_URL=http://localhost:11434 + +# For Azure OpenAI: +# AZURE_OPENAI_API_KEY=your-azure-key +# AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com + +# For Google Vertex AI: +# GOOGLE_VERTEX_PROJECT_ID=your-project-id + +# For AWS Bedrock: +# AWS_PROFILE=your-profile + +# For Hugging Face: +# HUGGINGFACEHUB_API_TOKEN=your-hf-token ``` -> ⚠️ **Note:** At minimum, set your preferred provider's API key. Without it, your agents will sleep forever! 💤 +> ⚠️ **Note:** Set your preferred provider's API key. Priority: Anthropic > Google Vertex > Google GenAI > Azure > Groq > Mistral > Cohere > Bedrock > HuggingFace > Ollama > OpenAI (default fallback). ### 2. Build & Run No `pip`, no `virtualenv`, no *"it works on my machine"* excuses. @@ -141,11 +184,24 @@ bin/agent.sh chef -i "I have chicken, rice, and soy sauce. What can I make?"
🔑 Required Environment Variables -| Variable | Required? | Description | -|----------|-----------|-------------| -| `OPENAI_API_KEY` | 🟢 **Yes*** | OpenAI API key (*if using OpenAI) | -| `ANTHROPIC_API_KEY`| 🟢 **Yes*** | Anthropic API key (*if using Anthropic) | -| `OPENAI_MODEL_NAME` | ⚪ No | Model to use (default: `gpt-4o`/`gpt-4`) | +| Provider | Variable | Required? | Default Model | +|----------|-----------|-------------|---------------| +| **Anthropic** | `ANTHROPIC_API_KEY` | 🟢 **Yes*** | `claude-haiku-4-5-20251001` | +| **OpenAI** | `OPENAI_API_KEY` | 🟢 **Yes*** | `gpt-4o-mini` | +| **Azure OpenAI** | `AZURE_OPENAI_API_KEY`, `AZURE_OPENAI_ENDPOINT` | ⚪ No | `gpt-4o-mini` | +| **Google GenAI** | `GOOGLE_API_KEY` | ⚪ No | `gemini-2.0-flash-exp` | +| **Google Vertex AI** | `GOOGLE_VERTEX_PROJECT_ID` | ⚪ No | `gemini-2.0-flash-exp` | +| **Groq** | `GROQ_API_KEY` | ⚪ No | `llama-3.3-70b-versatile` | +| **Mistral AI** | `MISTRAL_API_KEY` | ⚪ No | `mistral-large-latest` | +| **Cohere** | `COHERE_API_KEY` | ⚪ No | `command-r-plus` | +| **AWS Bedrock** | `AWS_PROFILE` or `AWS_ACCESS_KEY_ID` | ⚪ No | `anthropic.claude-3-5-sonnet-20241022-v2:0` | +| **Ollama** | `OLLAMA_BASE_URL` | ⚪ No | `llama3.2` | +| **Hugging Face** | `HUGGINGFACEHUB_API_TOKEN` | ⚪ No | `meta-llama/Llama-3.2-3B-Instruct` | + +**Model Override Variables** (optional): +- `ANTHROPIC_MODEL_NAME`, `OPENAI_MODEL_NAME`, `AZURE_OPENAI_MODEL_NAME`, `GOOGLE_GENAI_MODEL_NAME`, `GROQ_MODEL_NAME`, etc. + +> ⚠️ **Note:** Only one provider's API key is required. The framework auto-detects which provider to use based on available credentials.
diff --git a/agentic-framework/pyproject.toml b/agentic-framework/pyproject.toml index b759290..c3ef0cc 100644 --- a/agentic-framework/pyproject.toml +++ b/agentic-framework/pyproject.toml @@ -27,6 +27,11 @@ dependencies = [ "tree-sitter==0.21.3", "tree-sitter-languages>=1.10.2", "requests>=2.32.5", + "langchain-groq>=1.1.2", + "langchain-mistralai>=1.1.1", + "langchain-cohere>=0.5.0", + "langchain-aws>=1.3.1", + "langchain-huggingface>=1.2.0", ] [project.scripts] diff --git a/agentic-framework/src/agentic_framework/constants.py b/agentic-framework/src/agentic_framework/constants.py index c9ba000..9333ef1 100644 --- a/agentic-framework/src/agentic_framework/constants.py +++ b/agentic-framework/src/agentic_framework/constants.py @@ -1,6 +1,6 @@ import os from pathlib import Path -from typing import Literal +from typing import Any, Literal from dotenv import load_dotenv @@ -9,21 +9,82 @@ BASE_DIR = Path(__file__).resolve().parent.parent.parent LOGS_DIR = BASE_DIR / "logs" -Provider = Literal["openai", "anthropic"] +Provider = Literal[ + "anthropic", + "openai", + "ollama", + "azure_openai", + "google_vertexai", + "google_genai", + "groq", + "mistralai", + "cohere", + "bedrock", + "huggingface", +] + +# Default models for each provider +DEFAULT_MODELS: dict[Provider, str] = { + "anthropic": "claude-haiku-4-5-20251001", + "openai": "gpt-4o-mini", + "ollama": "llama3.2", + "azure_openai": "gpt-4o-mini", + "google_vertexai": "gemini-2.0-flash-exp", + "google_genai": "gemini-2.0-flash-exp", + "groq": "llama-3.3-70b-versatile", + "mistralai": "mistral-large-latest", + "cohere": "command-r-plus", + "bedrock": "anthropic.claude-3-5-sonnet-20241022-v2:0", + "huggingface": "meta-llama/Llama-3.2-3B-Instruct", +} def detect_provider() -> Provider: """Detect which LLM provider to use based on available API keys. Returns: - "anthropic" if ANTHROPIC_API_KEY is set, "openai" otherwise. + The detected provider name. Priority order: + 1. anthropic (ANTHROPIC_API_KEY) + 2. google_vertexai (GOOGLE_VERTEX_PROJECT_ID or GOOGLE_VERTEX_CREDENTIALS) + 3. google_genai (GOOGLE_API_KEY) + 4. azure_openai (AZURE_OPENAI_API_KEY) + 5. groq (GROQ_API_KEY) + 6. mistralai (MISTRAL_API_KEY) + 7. cohere (COHERE_API_KEY) + 8. bedrock (AWS_PROFILE or AWS_ACCESS_KEY_ID) + 9. huggingface (HUGGINGFACEHUB_API_TOKEN) + 10. ollama (OLLAMA_BASE_URL or localhost:11434) + 11. openai (OPENAI_API_KEY) + 12. openai (fallback) Note: - OpenAI is the default fallback when ANTHROPIC_API_KEY is absent. - When both keys are available, Anthropic takes precedence. + Ollama is special as it runs locally without an API key. + It's checked via OLLAMA_BASE_URL environment variable. """ + # Check in order of priority if os.getenv("ANTHROPIC_API_KEY"): return "anthropic" + if os.getenv("GOOGLE_VERTEX_PROJECT_ID") or os.getenv("GOOGLE_VERTEX_CREDENTIALS"): + return "google_vertexai" + if os.getenv("GOOGLE_API_KEY"): + return "google_genai" + if os.getenv("AZURE_OPENAI_API_KEY"): + return "azure_openai" + if os.getenv("GROQ_API_KEY"): + return "groq" + if os.getenv("MISTRAL_API_KEY"): + return "mistralai" + if os.getenv("COHERE_API_KEY"): + return "cohere" + if os.getenv("AWS_PROFILE") or os.getenv("AWS_ACCESS_KEY_ID"): + return "bedrock" + if os.getenv("HUGGINGFACEHUB_API_TOKEN"): + return "huggingface" + if os.getenv("OLLAMA_BASE_URL") or os.getenv("OLLAMA_ENABLED"): + return "ollama" + # Final fallback + if os.getenv("OPENAI_API_KEY"): + return "openai" return "openai" @@ -31,17 +92,120 @@ def get_default_model() -> str: """Get the default model name based on available provider. Returns: - Default model name for the detected provider. - - Examples: - - Anthropic: "claude-haiku-4-5-20251001" - - OpenAI: "gpt-4o-mini" + Default model name for the detected provider. Can be overridden + with environment variables like ANTHROPIC_MODEL_NAME, OPENAI_MODEL_NAME, etc. """ provider = detect_provider() - if provider == "anthropic": - return os.getenv("ANTHROPIC_MODEL_NAME", "claude-haiku-4-5-20251001") - return os.getenv("OPENAI_MODEL_NAME", "gpt-4o-mini") + + # Allow override via environment variables + env_model_names = { + "anthropic": os.getenv("ANTHROPIC_MODEL_NAME"), + "openai": os.getenv("OPENAI_MODEL_NAME"), + "ollama": os.getenv("OLLAMA_MODEL_NAME"), + "azure_openai": os.getenv("AZURE_OPENAI_MODEL_NAME"), + "google_vertexai": os.getenv("GOOGLE_VERTEX_MODEL_NAME"), + "google_genai": os.getenv("GOOGLE_GENAI_MODEL_NAME"), + "groq": os.getenv("GROQ_MODEL_NAME"), + "mistralai": os.getenv("MISTRAL_MODEL_NAME"), + "cohere": os.getenv("COHERE_MODEL_NAME"), + "bedrock": os.getenv("BEDROCK_MODEL_NAME"), + "huggingface": os.getenv("HUGGINGFACE_MODEL_NAME"), + } + + if env_model_name := env_model_names.get(provider): + return env_model_name + + return DEFAULT_MODELS.get(provider, "gpt-4o-mini") # Legacy constant for backward compatibility DEFAULT_MODEL = get_default_model() + + +def _create_model(model_name: str, temperature: float) -> Any: + """Create the appropriate LLM model instance based on detected provider. + + Args: + model_name: Name of the model to use. + temperature: Temperature setting for the model. + + Returns: + The appropriate Chat model instance for the detected provider. + """ + provider = detect_provider() + + if provider == "anthropic": + from langchain_anthropic import ChatAnthropic + + return ChatAnthropic(model=model_name, temperature=temperature) # type: ignore[call-arg] + + if provider == "ollama": + from langchain_community.chat_models import ChatOllama + + return ChatOllama( + model=model_name, + temperature=temperature, + base_url=os.getenv("OLLAMA_BASE_URL", "http://localhost:11434"), + ) + + if provider == "azure_openai": + from langchain_openai import AzureChatOpenAI + from pydantic.types import SecretStr + + api_key = os.getenv("AZURE_OPENAI_API_KEY") + return AzureChatOpenAI( + model=model_name, + temperature=temperature, + api_key=SecretStr(api_key) if api_key else None, + azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT"), + api_version=os.getenv("AZURE_OPENAI_API_VERSION", "2024-08-01-preview"), + azure_deployment=os.getenv("AZURE_OPENAI_DEPLOYMENT_NAME"), + ) + + if provider == "google_vertexai": + from langchain_google_vertexai import ChatVertexAI + + return ChatVertexAI(model=model_name, temperature=temperature) + + if provider == "google_genai": + from langchain_google_genai import ChatGoogleGenerativeAI + + return ChatGoogleGenerativeAI(model=model_name, temperature=temperature) + + if provider == "groq": + from langchain_groq import ChatGroq + + return ChatGroq(model=model_name, temperature=temperature) + + if provider == "mistralai": + from langchain_mistralai import ChatMistralAI + + return ChatMistralAI(model_name=model_name, temperature=temperature) + + if provider == "cohere": + from langchain_cohere import ChatCohere + + return ChatCohere(model=model_name, temperature=temperature) + + if provider == "bedrock": + from langchain_aws import ChatBedrock + + # Set AWS region via environment variable if specified + if bedrock_region := os.getenv("BEDROCK_REGION"): + os.environ["AWS_DEFAULT_REGION"] = bedrock_region + + return ChatBedrock(model=model_name, temperature=temperature) + + if provider == "huggingface": + from langchain_huggingface import ChatHuggingFace + + # HuggingFace ChatModel may not support temperature in all cases + try: + return ChatHuggingFace(model_id=model_name, temperature=temperature) + except Exception: + return ChatHuggingFace(model_id=model_name) + + # Default fallback to OpenAI + from langchain_openai import ChatOpenAI + + return ChatOpenAI(model=model_name, temperature=temperature) diff --git a/agentic-framework/src/agentic_framework/core/langgraph_agent.py b/agentic-framework/src/agentic_framework/core/langgraph_agent.py index 2e57cfd..0fc7c6d 100644 --- a/agentic-framework/src/agentic_framework/core/langgraph_agent.py +++ b/agentic-framework/src/agentic_framework/core/langgraph_agent.py @@ -2,32 +2,14 @@ from typing import Any, Dict, List, Sequence, Union from langchain.agents import create_agent -from langchain_anthropic import ChatAnthropic from langchain_core.messages import BaseMessage, HumanMessage -from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import InMemorySaver -from agentic_framework.constants import detect_provider, get_default_model +from agentic_framework.constants import _create_model, get_default_model from agentic_framework.interfaces.base import Agent from agentic_framework.mcp import MCPProvider -def _create_model(model_name: str, temperature: float): # type: ignore[no-any-return] - """Create the appropriate LLM model instance based on detected provider. - - Args: - model_name: Name of the model to use. - temperature: Temperature setting for the model. - - Returns: - Either ChatAnthropic or ChatOpenAI instance. - """ - provider = detect_provider() - if provider == "anthropic": - return ChatAnthropic(model=model_name, temperature=temperature) # type: ignore[call-arg] - return ChatOpenAI(model=model_name, temperature=temperature) - - class LangGraphMCPAgent(Agent): """Reusable base class for LangGraph agents with optional MCP tools.""" diff --git a/agentic-framework/src/agentic_framework/core/simple_agent.py b/agentic-framework/src/agentic_framework/core/simple_agent.py index 694b95f..bf943ea 100644 --- a/agentic-framework/src/agentic_framework/core/simple_agent.py +++ b/agentic-framework/src/agentic_framework/core/simple_agent.py @@ -1,31 +1,13 @@ from typing import Any, Dict, List, Union -from langchain_anthropic import ChatAnthropic from langchain_core.messages import BaseMessage from langchain_core.prompts import ChatPromptTemplate -from langchain_openai import ChatOpenAI -from agentic_framework.constants import detect_provider, get_default_model +from agentic_framework.constants import _create_model, get_default_model from agentic_framework.interfaces.base import Agent from agentic_framework.registry import AgentRegistry -def _create_model(model_name: str, temperature: float): # type: ignore[no-any-return] - """Create the appropriate LLM model instance based on detected provider. - - Args: - model_name: Name of the model to use. - temperature: Temperature setting for the model. - - Returns: - Either ChatAnthropic or ChatOpenAI instance. - """ - provider = detect_provider() - if provider == "anthropic": - return ChatAnthropic(model=model_name, temperature=temperature) # type: ignore[call-arg] - return ChatOpenAI(model=model_name, temperature=temperature) - - @AgentRegistry.register("simple", mcp_servers=None) class SimpleAgent(Agent): """ diff --git a/agentic-framework/tests/test_constants.py b/agentic-framework/tests/test_constants.py new file mode 100644 index 0000000..1feaa8b --- /dev/null +++ b/agentic-framework/tests/test_constants.py @@ -0,0 +1,928 @@ +"""Tests for provider detection and model creation in constants.py.""" + +import os +from typing import get_args + +import pytest + +# Mark tests that require external services or credentials +requires_external_service = pytest.mark.skip(reason="Requires external service credentials") + + +@pytest.fixture(autouse=True) +def reset_env(): + """Reset environment variables before each test.""" + # Save original env vars + original = dict(os.environ) + + yield + + # Restore original env vars + os.environ.clear() + os.environ.update(original) + + +class TestDetectProvider: + """Tests for detect_provider() function.""" + + def test_detect_anthropic_provider(self, monkeypatch): + """Test provider detection returns anthropic when ANTHROPIC_API_KEY is set.""" + # Clear all provider env vars first + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("ANTHROPIC_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "anthropic" + + def test_detect_google_vertexai_provider(self, monkeypatch): + """Test provider detection returns google_vertexai when GOOGLE_VERTEX_PROJECT_ID is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GOOGLE_VERTEX_PROJECT_ID", "test-project") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "google_vertexai" + + def test_detect_google_vertexai_credentials(self, monkeypatch): + """Test provider detection returns google_vertexai when GOOGLE_VERTEX_CREDENTIALS is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GOOGLE_VERTEX_CREDENTIALS", "test-credentials") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "google_vertexai" + + def test_detect_google_genai_provider(self, monkeypatch): + """Test provider detection returns google_genai when GOOGLE_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GOOGLE_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "google_genai" + + def test_detect_azure_openai_provider(self, monkeypatch): + """Test provider detection returns azure_openai when AZURE_OPENAI_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("AZURE_OPENAI_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "azure_openai" + + def test_detect_groq_provider(self, monkeypatch): + """Test provider detection returns groq when GROQ_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GROQ_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "groq" + + def test_detect_mistralai_provider(self, monkeypatch): + """Test provider detection returns mistralai when MISTRAL_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("MISTRAL_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "mistralai" + + def test_detect_cohere_provider(self, monkeypatch): + """Test provider detection returns cohere when COHERE_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("COHERE_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "cohere" + + def test_detect_bedrock_provider_aws_profile(self, monkeypatch): + """Test provider detection returns bedrock when AWS_PROFILE is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("AWS_PROFILE", "test-profile") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "bedrock" + + def test_detect_bedrock_provider_aws_access_key(self, monkeypatch): + """Test provider detection returns bedrock when AWS_ACCESS_KEY_ID is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("AWS_ACCESS_KEY_ID", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "bedrock" + + def test_detect_huggingface_provider(self, monkeypatch): + """Test provider detection returns huggingface when HUGGINGFACEHUB_API_TOKEN is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("HUGGINGFACEHUB_API_TOKEN", "test-token") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "huggingface" + + def test_detect_ollama_provider_base_url(self, monkeypatch): + """Test provider detection returns ollama when OLLAMA_BASE_URL is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OLLAMA_BASE_URL", "http://localhost:11434") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "ollama" + + def test_detect_ollama_provider_enabled(self, monkeypatch): + """Test provider detection returns ollama when OLLAMA_ENABLED is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OLLAMA_ENABLED", "true") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "ollama" + + def test_detect_openai_provider(self, monkeypatch): + """Test provider detection returns openai when OPENAI_API_KEY is set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OPENAI_API_KEY", "test-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "openai" + + def test_detect_fallback_to_openai(self, monkeypatch): + """Test provider detection falls back to openai when no keys are set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + from agentic_framework.constants import detect_provider + + assert detect_provider() == "openai" + + def test_priority_anthropic_over_others(self, monkeypatch): + """Test Anthropic has highest priority when multiple keys are set.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("ANTHROPIC_API_KEY", "anthropic-key") + monkeypatch.setenv("OPENAI_API_KEY", "openai-key") + monkeypatch.setenv("GOOGLE_API_KEY", "google-key") + from agentic_framework.constants import detect_provider + + assert detect_provider() == "anthropic" + + +class TestGetDefaultModel: + """Tests for get_default_model() function.""" + + def test_default_model_anthropic(self, monkeypatch): + """Test default model for Anthropic provider.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + "MODEL_NAME", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("ANTHROPIC_API_KEY", "test-key") + from agentic_framework.constants import get_default_model + + assert get_default_model() == "claude-haiku-4-5-20251001" + + def test_default_model_openai(self, monkeypatch): + """Test default model for OpenAI provider.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + "MODEL_NAME", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OPENAI_API_KEY", "test-key") + from agentic_framework.constants import get_default_model + + assert get_default_model() == "gpt-4o-mini" + + def test_default_model_ollama(self, monkeypatch): + """Test default model for Ollama provider.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + "MODEL_NAME", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OLLAMA_BASE_URL", "http://localhost:11434") + from agentic_framework.constants import get_default_model + + assert get_default_model() == "llama3.2" + + def test_default_model_groq(self, monkeypatch): + """Test default model for Groq provider.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + "MODEL_NAME", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GROQ_API_KEY", "test-key") + from agentic_framework.constants import get_default_model + + assert get_default_model() == "llama-3.3-70b-versatile" + + def test_default_model_override(self, monkeypatch): + """Test model override via environment variable.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + "MODEL_NAME", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("ANTHROPIC_API_KEY", "test-key") + monkeypatch.setenv("ANTHROPIC_MODEL_NAME", "claude-opus-4") + from agentic_framework.constants import get_default_model + + assert get_default_model() == "claude-opus-4" + + def test_all_default_models_defined(self): + """Test that all providers have default models defined.""" + from agentic_framework.constants import DEFAULT_MODELS, Provider + + provider_types = get_args(Provider) + for provider in provider_types: + assert provider in DEFAULT_MODELS, f"Missing default model for provider: {provider}" + + +class TestCreateModel: + """Tests for _create_model() function.""" + + def test_create_anthropic_model(self, monkeypatch): + """Test creating Anthropic model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("ANTHROPIC_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("claude-3-opus", 0.7) + assert model.__class__.__name__ == "ChatAnthropic" + assert model.model == "claude-3-opus" + assert model.temperature == 0.7 + + def test_create_openai_model(self, monkeypatch): + """Test creating OpenAI model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OPENAI_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("gpt-4", 0.5) + assert model.__class__.__name__ == "ChatOpenAI" + model_attr = getattr(model, "model_name", model.model if hasattr(model, "model") else None) + assert model_attr == "gpt-4" + assert model.temperature == 0.5 + + def test_create_ollama_model(self, monkeypatch): + """Test creating Ollama model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OLLAMA_BASE_URL", "http://localhost:11434") + from agentic_framework.constants import _create_model + + model = _create_model("llama3.2", 0.8) + assert model.__class__.__name__ == "ChatOllama" + assert model.model == "llama3.2" + assert model.temperature == 0.8 + assert model.base_url == "http://localhost:11434" + + def test_create_ollama_model_custom_base_url(self, monkeypatch): + """Test creating Ollama model with custom base URL.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("OLLAMA_BASE_URL", "http://remote-host:11434") + from agentic_framework.constants import _create_model + + model = _create_model("llama3.2", 0.5) + assert model.base_url == "http://remote-host:11434" + + def test_create_groq_model(self, monkeypatch): + """Test creating Groq model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GROQ_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("llama-3.3-70b-versatile", 0.3) + assert model.__class__.__name__ == "ChatGroq" + model_attr = getattr(model, "model_name", model.model if hasattr(model, "model") else None) + assert model_attr == "llama-3.3-70b-versatile" + assert model.temperature == 0.3 + + def test_create_mistralai_model(self, monkeypatch): + """Test creating MistralAI model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("MISTRAL_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("mistral-large-latest", 0.6) + assert model.__class__.__name__ == "ChatMistralAI" + # MistralAI uses 'model' attribute + model_attr = getattr(model, "model", model.model_name if hasattr(model, "model_name") else None) + assert model_attr == "mistral-large-latest" + assert model.temperature == 0.6 + + def test_create_cohere_model(self, monkeypatch): + """Test creating Cohere model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("COHERE_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("command-r-plus", 0.4) + assert model.__class__.__name__ == "ChatCohere" + assert model.model == "command-r-plus" + assert model.temperature == 0.4 + + def test_create_huggingface_model(self, monkeypatch): + """Test creating HuggingFace model - requires transformers library.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("HUGGINGFACEHUB_API_TOKEN", "test-token") + from agentic_framework.constants import _create_model + + try: + model = _create_model("meta-llama/Llama-3.2-3B-Instruct", 0.2) + assert model.__class__.__name__ == "ChatHuggingFace" + # HuggingFace uses model_id parameter + model_attr = getattr(model, "model_id", model.model if hasattr(model, "model") else None) + assert model_attr == "meta-llama/Llama-3.2-3B-Instruct" + except Exception as e: + # Skip if transformers library is not installed + pytest.skip(f"HuggingFace provider requires transformers library: {e}") + + def test_create_azure_openai_model(self, monkeypatch): + """Test creating Azure OpenAI model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("AZURE_OPENAI_API_KEY", "test-key") + monkeypatch.setenv("AZURE_OPENAI_ENDPOINT", "https://test.openai.azure.com") + from agentic_framework.constants import _create_model + + model = _create_model("gpt-4", 0.5) + assert model.__class__.__name__ == "AzureChatOpenAI" + model_attr = getattr(model, "model_name", model.model if hasattr(model, "model") else None) + assert model_attr == "gpt-4" + assert model.temperature == 0.5 + assert str(model.azure_endpoint) == "https://test.openai.azure.com" + + def test_create_google_genai_model(self, monkeypatch): + """Test creating Google GenAI model.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GOOGLE_API_KEY", "test-key") + from agentic_framework.constants import _create_model + + model = _create_model("gemini-2.0-flash-exp", 0.7) + assert model.__class__.__name__ == "ChatGoogleGenerativeAI" + model_attr = getattr(model, "model_name", model.model if hasattr(model, "model") else None) + assert model_attr == "gemini-2.0-flash-exp" + assert model.temperature == 0.7 + + @requires_external_service + def test_create_google_vertexai_model(self, monkeypatch): + """Test creating Google VertexAI model - requires credentials.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("GOOGLE_VERTEX_PROJECT_ID", "test-project") + from agentic_framework.constants import _create_model + + model = _create_model("gemini-2.0-flash-exp", 0.6) + assert model.__class__.__name__ == "ChatVertexAI" + model_attr = getattr(model, "model_name", model.model if hasattr(model, "model") else None) + assert model_attr == "gemini-2.0-flash-exp" + assert model.temperature == 0.6 + + @requires_external_service + def test_create_bedrock_model(self, monkeypatch): + """Test creating Bedrock model - requires credentials.""" + for key in list(os.environ.keys()): + if any( + x in key.upper() + for x in [ + "ANTHROPIC", + "GOOGLE", + "AZURE", + "GROQ", + "MISTRAL", + "COHERE", + "AWS", + "HUGGINGFACE", + "OLLAMA", + "OPENAI", + ] + ): + monkeypatch.delenv(key, raising=False) + + monkeypatch.setenv("AWS_PROFILE", "test-profile") + from agentic_framework.constants import _create_model + + model = _create_model("anthropic.claude-3-5-sonnet-20241022-v2:0", 0.5) + assert model.__class__.__name__ == "ChatBedrock" + # Bedrock uses model_id + model_attr = getattr(model, "model_id", model.model if hasattr(model, "model") else None) + assert model_attr == "anthropic.claude-3-5-sonnet-20241022-v2:0" + assert model.temperature == 0.5 diff --git a/agentic-framework/tests/test_core_agents.py b/agentic-framework/tests/test_core_agents.py index 12562fe..89ebb9e 100644 --- a/agentic-framework/tests/test_core_agents.py +++ b/agentic-framework/tests/test_core_agents.py @@ -12,7 +12,7 @@ async def ainvoke(self, payload, config): def test_chef_agent_prompt_and_mcp(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = ChefAgent(initial_mcp_tools=[]) @@ -24,7 +24,7 @@ def test_chef_agent_prompt_and_mcp(monkeypatch): def test_travel_and_news_prompts(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) travel = TravelAgent(initial_mcp_tools=[]) diff --git a/agentic-framework/tests/test_developer_agent.py b/agentic-framework/tests/test_developer_agent.py index 104b3e9..9cf68af 100644 --- a/agentic-framework/tests/test_developer_agent.py +++ b/agentic-framework/tests/test_developer_agent.py @@ -10,7 +10,7 @@ async def ainvoke(self, payload, config): def test_developer_agent_system_prompt(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -25,7 +25,7 @@ def test_developer_agent_system_prompt(monkeypatch): def test_developer_agent_local_tools_count(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -46,7 +46,7 @@ def test_developer_agent_local_tools_count(monkeypatch): def test_developer_agent_tool_descriptions(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -64,7 +64,7 @@ def test_developer_agent_tool_descriptions(monkeypatch): def test_developer_agent_run(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -74,7 +74,7 @@ def test_developer_agent_run(monkeypatch): def test_developer_agent_with_mcp_tools(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # Simulate MCP tools diff --git a/agentic-framework/tests/test_github_pr_reviewer_agent.py b/agentic-framework/tests/test_github_pr_reviewer_agent.py index f1d7998..c08b18b 100644 --- a/agentic-framework/tests/test_github_pr_reviewer_agent.py +++ b/agentic-framework/tests/test_github_pr_reviewer_agent.py @@ -26,7 +26,7 @@ async def ainvoke(self, payload: dict, config: dict) -> dict: def test_github_pr_reviewer_system_prompt(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -41,7 +41,7 @@ def test_github_pr_reviewer_system_prompt(monkeypatch: object) -> None: def test_github_pr_reviewer_tools_count(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -62,7 +62,7 @@ def test_github_pr_reviewer_tools_count(monkeypatch: object) -> None: def test_github_pr_reviewer_tool_descriptions(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -77,7 +77,7 @@ def test_github_pr_reviewer_tool_descriptions(monkeypatch: object) -> None: def test_github_pr_reviewer_run(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) diff --git a/agentic-framework/tests/test_travel_coordinator_agent.py b/agentic-framework/tests/test_travel_coordinator_agent.py index 6fd4046..f222b2a 100644 --- a/agentic-framework/tests/test_travel_coordinator_agent.py +++ b/agentic-framework/tests/test_travel_coordinator_agent.py @@ -22,7 +22,7 @@ async def ainvoke(self, payload, config): def test_travel_coordinator_orchestrates_three_specialists(monkeypatch): calls: list[tuple[str, dict, dict]] = [] - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) def fake_create_agent(**kwargs): system_prompt = kwargs["system_prompt"] @@ -52,7 +52,7 @@ def fake_create_agent(**kwargs): def test_travel_coordinator_get_tools_aggregates_from_specialists(monkeypatch): - monkeypatch.setattr("agentic_framework.core.langgraph_agent.ChatOpenAI", lambda **kwargs: object()) + monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) monkeypatch.setattr( "agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph("review", []), diff --git a/agentic-framework/uv.lock b/agentic-framework/uv.lock index db02931..0866239 100644 --- a/agentic-framework/uv.lock +++ b/agentic-framework/uv.lock @@ -14,11 +14,16 @@ dependencies = [ { name = "dotenv" }, { name = "langchain" }, { name = "langchain-anthropic" }, + { name = "langchain-aws" }, + { name = "langchain-cohere" }, { name = "langchain-community" }, { name = "langchain-core" }, { name = "langchain-google-genai" }, { name = "langchain-google-vertexai" }, + { name = "langchain-groq" }, + { name = "langchain-huggingface" }, { name = "langchain-mcp-adapters" }, + { name = "langchain-mistralai" }, { name = "langchain-model-profiles" }, { name = "langchain-openai" }, { name = "langchain-text-splitters" }, @@ -48,11 +53,16 @@ requires-dist = [ { name = "dotenv", specifier = ">=0.9.9" }, { name = "langchain", specifier = ">=1.1.3" }, { name = "langchain-anthropic", specifier = ">=1.0.3" }, + { name = "langchain-aws", specifier = ">=1.3.1" }, + { name = "langchain-cohere", specifier = ">=0.5.0" }, { name = "langchain-community", specifier = ">=0.4.1" }, { name = "langchain-core", specifier = ">=1.1.3" }, { name = "langchain-google-genai", specifier = ">=3.1.0" }, { name = "langchain-google-vertexai", specifier = ">=3.0.3" }, + { name = "langchain-groq", specifier = ">=1.1.2" }, + { name = "langchain-huggingface", specifier = ">=1.2.0" }, { name = "langchain-mcp-adapters", specifier = ">=0.1.13" }, + { name = "langchain-mistralai", specifier = ">=1.1.1" }, { name = "langchain-model-profiles", specifier = ">=0.0.4" }, { name = "langchain-openai", specifier = ">=1.1.1" }, { name = "langchain-text-splitters", specifier = ">=1.0.0" }, @@ -212,6 +222,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/95/c1/84fc6811122f54b20de2e5afb312ee07a3a47a328755587d1e505475239b/blockbuster-1.5.26-py3-none-any.whl", hash = "sha256:f8e53fb2dd4b6c6ec2f04907ddbd063ca7cd1ef587d24448ef4e50e81e3a79bb", size = 13226, upload-time = "2025-12-05T10:43:48.778Z" }, ] +[[package]] +name = "boto3" +version = "1.42.59" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, + { name = "jmespath" }, + { name = "s3transfer" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/4e/499cb52aaee9468c346bcc1158965e24e72b4e2a20052725b680e0ac949b/boto3-1.42.59.tar.gz", hash = "sha256:6c4a14a4eb37b58a9048901bdeefbe1c529638b73e8f55413319a25f010ca211", size = 112725, upload-time = "2026-02-27T20:25:33.228Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/c0/22d868b9408dc5a33935a72896ec8d638b2766c459668d1b37c3e5ac2066/boto3-1.42.59-py3-none-any.whl", hash = "sha256:7a66e3e8e2087ea4403e135e9de592e6d63fc9a91080d8dac415bb74df873a72", size = 140557, upload-time = "2026-02-27T20:25:31.774Z" }, +] + +[[package]] +name = "botocore" +version = "1.42.59" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/ae/50fb33bdf1911c216d50f98d989dd032a506f054cf829ebd737c6fa7e3e6/botocore-1.42.59.tar.gz", hash = "sha256:5314f19e1da8fc0ebc41bdb8bbe17c9a7397d87f4d887076ac8bdef972a34138", size = 14950271, upload-time = "2026-02-27T20:25:20.614Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/df/9d52819e0d804ead073d53ab1823bc0f0cb172a250fba31107b0b43fbb04/botocore-1.42.59-py3-none-any.whl", hash = "sha256:d2f2ff7ecc31e86ef46b5daee112cfbca052c13801285fb23af909f7bff5b657", size = 14619293, upload-time = "2026-02-27T20:25:17.455Z" }, +] + [[package]] name = "bottleneck" version = "1.6.0" @@ -350,6 +388,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/39/799be3f2f0f38cc727ee3b4f1445fe6d5e4133064ec2e4115069418a5bb6/cloudpickle-3.1.2-py3-none-any.whl", hash = "sha256:9acb47f6afd73f60dc1df93bb801b472f05ff42fa6c84167d25cb206be1fbf4a", size = 22228, upload-time = "2025-11-03T09:25:25.534Z" }, ] +[[package]] +name = "cohere" +version = "5.20.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fastavro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "pydantic-core" }, + { name = "requests" }, + { name = "tokenizers" }, + { name = "types-requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/44/0b/96e2b55a0114ed9d69b3154565f54b764e7530735426290b000f467f4c0f/cohere-5.20.7.tar.gz", hash = "sha256:997ed85fabb3a1e4a4c036fdb520382e7bfa670db48eb59a026803b6f7061dbb", size = 184986, upload-time = "2026-02-25T01:22:18.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/86/dc991a75e3b9c2007b90dbfaf7f36fdb2457c216f799e26ce0474faf0c1f/cohere-5.20.7-py3-none-any.whl", hash = "sha256:043fef2a12c30c07e9b2c1f0b869fd66ffd911f58d1492f87e901c4190a65914", size = 323389, upload-time = "2026-02-25T01:22:16.902Z" }, +] + [[package]] name = "colorama" version = "0.4.6" @@ -501,6 +558,40 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b2/b7/545d2c10c1fc15e48653c91efde329a790f2eecfbbf2bd16003b5db2bab0/dotenv-0.9.9-py2.py3-none-any.whl", hash = "sha256:29cf74a087b31dafdb5a446b6d7e11cbce8ed2741540e2339c69fbef92c94ce9", size = 1892, upload-time = "2025-02-19T22:15:01.647Z" }, ] +[[package]] +name = "fastavro" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/65/8b/fa2d3287fd2267be6261d0177c6809a7fa12c5600ddb33490c8dc29e77b2/fastavro-1.12.1.tar.gz", hash = "sha256:2f285be49e45bc047ab2f6bed040bb349da85db3f3c87880e4b92595ea093b2b", size = 1025661, upload-time = "2025-10-10T15:40:55.41Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/f0/10bd1a3d08667fa0739e2b451fe90e06df575ec8b8ba5d3135c70555c9bd/fastavro-1.12.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:509818cb24b98a804fc80be9c5fed90f660310ae3d59382fc811bfa187122167", size = 1009057, upload-time = "2025-10-10T15:41:24.556Z" }, + { url = "https://files.pythonhosted.org/packages/78/ad/0d985bc99e1fa9e74c636658000ba38a5cd7f5ab2708e9c62eaf736ecf1a/fastavro-1.12.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:089e155c0c76e0d418d7e79144ce000524dd345eab3bc1e9c5ae69d500f71b14", size = 3391866, upload-time = "2025-10-10T15:41:26.882Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9e/b4951dc84ebc34aac69afcbfbb22ea4a91080422ec2bfd2c06076ff1d419/fastavro-1.12.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44cbff7518901c91a82aab476fcab13d102e4999499df219d481b9e15f61af34", size = 3458005, upload-time = "2025-10-10T15:41:29.017Z" }, + { url = "https://files.pythonhosted.org/packages/af/f8/5a8df450a9f55ca8441f22ea0351d8c77809fc121498b6970daaaf667a21/fastavro-1.12.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a275e48df0b1701bb764b18a8a21900b24cf882263cb03d35ecdba636bbc830b", size = 3295258, upload-time = "2025-10-10T15:41:31.564Z" }, + { url = "https://files.pythonhosted.org/packages/99/b2/40f25299111d737e58b85696e91138a66c25b7334f5357e7ac2b0e8966f8/fastavro-1.12.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2de72d786eb38be6b16d556b27232b1bf1b2797ea09599507938cdb7a9fe3e7c", size = 3430328, upload-time = "2025-10-10T15:41:33.689Z" }, + { url = "https://files.pythonhosted.org/packages/e0/07/85157a7c57c5f8b95507d7829b5946561e5ee656ff80e9dd9a757f53ddaf/fastavro-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:9090f0dee63fe022ee9cc5147483366cc4171c821644c22da020d6b48f576b4f", size = 444140, upload-time = "2025-10-10T15:41:34.902Z" }, + { url = "https://files.pythonhosted.org/packages/bb/57/26d5efef9182392d5ac9f253953c856ccb66e4c549fd3176a1e94efb05c9/fastavro-1.12.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:78df838351e4dff9edd10a1c41d1324131ffecbadefb9c297d612ef5363c049a", size = 1000599, upload-time = "2025-10-10T15:41:36.554Z" }, + { url = "https://files.pythonhosted.org/packages/33/cb/8ab55b21d018178eb126007a56bde14fd01c0afc11d20b5f2624fe01e698/fastavro-1.12.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:780476c23175d2ae457c52f45b9ffa9d504593499a36cd3c1929662bf5b7b14b", size = 3335933, upload-time = "2025-10-10T15:41:39.07Z" }, + { url = "https://files.pythonhosted.org/packages/fe/03/9c94ec9bf873eb1ffb0aa694f4e71940154e6e9728ddfdc46046d7e8ced4/fastavro-1.12.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0714b285160fcd515eb0455540f40dd6dac93bdeacdb03f24e8eac3d8aa51f8d", size = 3402066, upload-time = "2025-10-10T15:41:41.608Z" }, + { url = "https://files.pythonhosted.org/packages/75/c8/cb472347c5a584ccb8777a649ebb28278fccea39d005fc7df19996f41df8/fastavro-1.12.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a8bc2dcec5843d499f2489bfe0747999108f78c5b29295d877379f1972a3d41a", size = 3240038, upload-time = "2025-10-10T15:41:43.743Z" }, + { url = "https://files.pythonhosted.org/packages/e1/77/569ce9474c40304b3a09e109494e020462b83e405545b78069ddba5f614e/fastavro-1.12.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b1921ac35f3d89090a5816b626cf46e67dbecf3f054131f84d56b4e70496f45", size = 3369398, upload-time = "2025-10-10T15:41:45.719Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1f/9589e35e9ea68035385db7bdbf500d36b8891db474063fb1ccc8215ee37c/fastavro-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:5aa777b8ee595b50aa084104cd70670bf25a7bbb9fd8bb5d07524b0785ee1699", size = 444220, upload-time = "2025-10-10T15:41:47.39Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d2/78435fe737df94bd8db2234b2100f5453737cffd29adee2504a2b013de84/fastavro-1.12.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c3d67c47f177e486640404a56f2f50b165fe892cc343ac3a34673b80cc7f1dd6", size = 1086611, upload-time = "2025-10-10T15:41:48.818Z" }, + { url = "https://files.pythonhosted.org/packages/b6/be/428f99b10157230ddac77ec8cc167005b29e2bd5cbe228345192bb645f30/fastavro-1.12.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5217f773492bac43dae15ff2931432bce2d7a80be7039685a78d3fab7df910bd", size = 3541001, upload-time = "2025-10-10T15:41:50.871Z" }, + { url = "https://files.pythonhosted.org/packages/16/08/a2eea4f20b85897740efe44887e1ac08f30dfa4bfc3de8962bdcbb21a5a1/fastavro-1.12.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:469fecb25cba07f2e1bfa4c8d008477cd6b5b34a59d48715e1b1a73f6160097d", size = 3432217, upload-time = "2025-10-10T15:41:53.149Z" }, + { url = "https://files.pythonhosted.org/packages/87/bb/b4c620b9eb6e9838c7f7e4b7be0762834443adf9daeb252a214e9ad3178c/fastavro-1.12.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d71c8aa841ef65cfab709a22bb887955f42934bced3ddb571e98fdbdade4c609", size = 3366742, upload-time = "2025-10-10T15:41:55.237Z" }, + { url = "https://files.pythonhosted.org/packages/3d/d1/e69534ccdd5368350646fea7d93be39e5f77c614cca825c990bd9ca58f67/fastavro-1.12.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:b81fc04e85dfccf7c028e0580c606e33aa8472370b767ef058aae2c674a90746", size = 3383743, upload-time = "2025-10-10T15:41:57.68Z" }, +] + +[[package]] +name = "filelock" +version = "3.24.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/92/a8e2479937ff39185d20dd6a851c1a63e55849e447a55e798cc2e1f49c65/filelock-3.24.3.tar.gz", hash = "sha256:011a5644dc937c22699943ebbfc46e969cdde3e171470a6e40b9533e5a72affa", size = 37935, upload-time = "2026-02-19T00:48:20.543Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/0f/5d0c71a1aefeb08efff26272149e07ab922b64f46c63363756224bd6872e/filelock-3.24.3-py3-none-any.whl", hash = "sha256:426e9a4660391f7f8a810d71b0555bce9008b0a1cc342ab1f6947d37639e002d", size = 24331, upload-time = "2026-02-19T00:48:18.465Z" }, +] + [[package]] name = "filetype" version = "1.2.0" @@ -573,6 +664,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, ] +[[package]] +name = "fsspec" +version = "2026.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/51/7c/f60c259dcbf4f0c47cc4ddb8f7720d2dcdc8888c8e5ad84c73ea4531cc5b/fsspec-2026.2.0.tar.gz", hash = "sha256:6544e34b16869f5aacd5b90bdf1a71acb37792ea3ddf6125ee69a22a53fb8bff", size = 313441, upload-time = "2026-02-05T21:50:53.743Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e6/ab/fb21f4c939bb440104cc2b396d3be1d9b7a9fd3c6c2a53d98c45b3d7c954/fsspec-2026.2.0-py3-none-any.whl", hash = "sha256:98de475b5cb3bd66bedd5c4679e87b4fdfe1a3bf4d707b151b3c07e58c9a2437", size = 202505, upload-time = "2026-02-05T21:50:51.819Z" }, +] + [[package]] name = "google-api-core" version = "2.29.0" @@ -812,6 +912,23 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/90/e7/824beda656097edee36ab15809fd063447b200cc03a7f6a24c34d520bc88/greenlet-3.3.1-cp313-cp313-win_arm64.whl", hash = "sha256:2f080e028001c5273e0b42690eaf359aeef9cb1389da0f171ea51a5dc3c7608d", size = 226294, upload-time = "2026-01-23T15:30:52.73Z" }, ] +[[package]] +name = "groq" +version = "0.37.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/78/18948a9056e1509c87e10ab8316a90ecce87035fbd53342dffdf97f4de00/groq-0.37.1.tar.gz", hash = "sha256:7353d6dfb60834fd7aacbb86af106e2dc2aeaff6d0edd65fb2fd0f16bd39314c", size = 145289, upload-time = "2025-12-04T18:08:07.118Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/d6/645a081750e43f858b7d09dce5d8e1e76cf11e7e4bdba81252e04f78963d/groq-0.37.1-py3-none-any.whl", hash = "sha256:b49f8c8898c55eaec9f71f1342f3fcacc9560d67a08ce5f35fbfb84e8dacd3da", size = 137494, upload-time = "2025-12-04T18:08:05.801Z" }, +] + [[package]] name = "grpc-google-iam-v1" version = "0.14.3" @@ -926,6 +1043,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "hf-xet" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/cb/9bb543bd987ffa1ee48202cc96a756951b734b79a542335c566148ade36c/hf_xet-1.3.2.tar.gz", hash = "sha256:e130ee08984783d12717444e538587fa2119385e5bd8fc2bb9f930419b73a7af", size = 643646, upload-time = "2026-02-27T17:26:08.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/75/462285971954269432aad2e7938c5c7ff9ec7d60129cec542ab37121e3d6/hf_xet-1.3.2-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:335a8f36c55fd35a92d0062f4e9201b4015057e62747b7e7001ffb203c0ee1d2", size = 3761019, upload-time = "2026-02-27T17:25:49.441Z" }, + { url = "https://files.pythonhosted.org/packages/35/56/987b0537ddaf88e17192ea09afa8eca853e55f39a4721578be436f8409df/hf_xet-1.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:c1ae4d3a716afc774e66922f3cac8206bfa707db13f6a7e62dfff74bfc95c9a8", size = 3521565, upload-time = "2026-02-27T17:25:47.469Z" }, + { url = "https://files.pythonhosted.org/packages/a8/5c/7e4a33a3d689f77761156cc34558047569e54af92e4d15a8f493229f6767/hf_xet-1.3.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d6dbdf231efac0b9b39adcf12a07f0c030498f9212a18e8c50224d0e84ab803d", size = 4176494, upload-time = "2026-02-27T17:25:40.247Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b3/71e856bf9d9a69b3931837e8bf22e095775f268c8edcd4a9e8c355f92484/hf_xet-1.3.2-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c1980abfb68ecf6c1c7983379ed7b1e2b49a1aaf1a5aca9acc7d48e5e2e0a961", size = 3955601, upload-time = "2026-02-27T17:25:38.376Z" }, + { url = "https://files.pythonhosted.org/packages/63/d7/aecf97b3f0a981600a67ff4db15e2d433389d698a284bb0ea5d8fcdd6f7f/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:1c88fbd90ad0d27c46b77a445f0a436ebaa94e14965c581123b68b1c52f5fd30", size = 4154770, upload-time = "2026-02-27T17:25:56.756Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e1/3af961f71a40e09bf5ee909842127b6b00f5ab4ee3817599dc0771b79893/hf_xet-1.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:35b855024ca37f2dd113ac1c08993e997fbe167b9d61f9ef66d3d4f84015e508", size = 4394161, upload-time = "2026-02-27T17:25:58.111Z" }, + { url = "https://files.pythonhosted.org/packages/a1/c3/859509bade9178e21b8b1db867b8e10e9f817ab9ac1de77cb9f461ced765/hf_xet-1.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:31612ba0629046e425ba50375685a2586e11fb9144270ebabd75878c3eaf6378", size = 3637377, upload-time = "2026-02-27T17:26:10.611Z" }, + { url = "https://files.pythonhosted.org/packages/05/7f/724cfbef4da92d577b71f68bf832961c8919f36c60d28d289a9fc9d024d4/hf_xet-1.3.2-cp313-cp313t-win_arm64.whl", hash = "sha256:433c77c9f4e132b562f37d66c9b22c05b5479f243a1f06a120c1c06ce8b1502a", size = 3497875, upload-time = "2026-02-27T17:26:09.034Z" }, + { url = "https://files.pythonhosted.org/packages/d8/28/dbb024e2e3907f6f3052847ca7d1a2f7a3972fafcd53ff79018977fcb3e4/hf_xet-1.3.2-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f93b7595f1d8fefddfede775c18b5c9256757824f7f6832930b49858483cd56f", size = 3763961, upload-time = "2026-02-27T17:25:52.537Z" }, + { url = "https://files.pythonhosted.org/packages/e4/71/b99aed3823c9d1795e4865cf437d651097356a3f38c7d5877e4ac544b8e4/hf_xet-1.3.2-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:a85d3d43743174393afe27835bde0cd146e652b5fcfdbcd624602daef2ef3259", size = 3526171, upload-time = "2026-02-27T17:25:50.968Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/907890ce6ef5598b5920514f255ed0a65f558f820515b18db75a51b2f878/hf_xet-1.3.2-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7c2a054a97c44e136b1f7f5a78f12b3efffdf2eed3abc6746fc5ea4b39511633", size = 4180750, upload-time = "2026-02-27T17:25:43.125Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ad/bc7f41f87173d51d0bce497b171c4ee0cbde1eed2d7b4216db5d0ada9f50/hf_xet-1.3.2-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:06b724a361f670ae557836e57801b82c75b534812e351a87a2c739f77d1e0635", size = 3961035, upload-time = "2026-02-27T17:25:41.837Z" }, + { url = "https://files.pythonhosted.org/packages/73/38/600f4dda40c4a33133404d9fe644f1d35ff2d9babb4d0435c646c63dd107/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:305f5489d7241a47e0458ef49334be02411d1d0f480846363c1c8084ed9916f7", size = 4161378, upload-time = "2026-02-27T17:26:00.365Z" }, + { url = "https://files.pythonhosted.org/packages/00/b3/7bc1ff91d1ac18420b7ad1e169b618b27c00001b96310a89f8a9294fe509/hf_xet-1.3.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:06cdbde243c85f39a63b28e9034321399c507bcd5e7befdd17ed2ccc06dfe14e", size = 4398020, upload-time = "2026-02-27T17:26:03.977Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0b/99bfd948a3ed3620ab709276df3ad3710dcea61976918cce8706502927af/hf_xet-1.3.2-cp37-abi3-win_amd64.whl", hash = "sha256:9298b47cce6037b7045ae41482e703c471ce36b52e73e49f71226d2e8e5685a1", size = 3641624, upload-time = "2026-02-27T17:26:13.542Z" }, + { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" }, +] + [[package]] name = "httpcore" version = "1.0.9" @@ -963,6 +1104,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/fd/6668e5aec43ab844de6fc74927e155a3b37bf40d7c3790e49fc0406b6578/httpx_sse-0.4.3-py3-none-any.whl", hash = "sha256:0ac1c9fe3c0afad2e0ebb25a934a59f4c7823b60792691f779fad2c5568830fc", size = 8960, upload-time = "2025-10-10T21:48:21.158Z" }, ] +[[package]] +name = "huggingface-hub" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/b7/8cb61d2eece5fb05a83271da168186721c450eb74e3c31f7ef3169fa475b/huggingface_hub-0.36.2.tar.gz", hash = "sha256:1934304d2fb224f8afa3b87007d58501acfda9215b334eed53072dd5e815ff7a", size = 649782, upload-time = "2026-02-06T09:24:13.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/af/48ac8483240de756d2438c380746e7130d1c6f75802ef22f3c6d49982787/huggingface_hub-0.36.2-py3-none-any.whl", hash = "sha256:48f0c8eac16145dfce371e9d2d7772854a4f591bcb56c9cf548accf531d54270", size = 566395, upload-time = "2026-02-06T09:24:11.133Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -1036,6 +1196,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/67/8a/a342b2f0251f3dac4ca17618265d93bf244a2a4d089126e81e4c1056ac50/jiter-0.13.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7bb00b6d26db67a05fe3e12c76edc75f32077fb51deed13822dc648fa373bc19", size = 343768, upload-time = "2026-02-02T12:37:55.055Z" }, ] +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -1134,6 +1303,21 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c9/6b/2da16c32308f79bb4588cec7095edbc770722ae4b3c3a1c135e05b0bdc2e/langchain_anthropic-1.3.2-py3-none-any.whl", hash = "sha256:35bc30862696a493680b898eb76bd6c866841f8e48a57d5eca1420a4fd807ac0", size = 46751, upload-time = "2026-02-06T16:14:44.734Z" }, ] +[[package]] +name = "langchain-aws" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "boto3" }, + { name = "langchain-core" }, + { name = "numpy" }, + { name = "pydantic" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7a/23/5c681e53480b046a255bd6525de49e7cac7e51b436525f7425a3bf5c7909/langchain_aws-1.3.1.tar.gz", hash = "sha256:2084a612ab965937329d4d9f4098e93277e23aef401dec001125fa3fd7ea751c", size = 425998, upload-time = "2026-02-27T01:16:18.631Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/7b/b254f9271613bc8a5b6f454e67b9ea62921bc3d6fc17ad232278b8266f97/langchain_aws-1.3.1-py3-none-any.whl", hash = "sha256:b4bc4ea4a763202a32f68eed1f7b3c40b59ce8fb9d113e47e9839de0cedee816", size = 170903, upload-time = "2026-02-27T01:16:17.388Z" }, +] + [[package]] name = "langchain-classic" version = "1.0.1" @@ -1152,6 +1336,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/0f/eab87f017d7fe28e8c11fff614f4cdbfae32baadb77d0f79e9f922af1df2/langchain_classic-1.0.1-py3-none-any.whl", hash = "sha256:131d83a02bb80044c68fedc1ab4ae885d5b8f8c2c742d8ab9e7534ad9cda8e80", size = 1040666, upload-time = "2025-12-23T22:55:21.025Z" }, ] +[[package]] +name = "langchain-cohere" +version = "0.5.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cohere" }, + { name = "langchain-community" }, + { name = "langchain-core" }, + { name = "pydantic" }, + { name = "types-pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6e/0c/4bb5110d846a01e8cca7ee6644297ceec65627556aa0fe7d74661faeaa3f/langchain_cohere-0.5.0.tar.gz", hash = "sha256:812ffaf73009cbc136596974fb5de40aab86bf5d1acb82dd07f876d53a4f0908", size = 36463, upload-time = "2025-11-04T14:02:39.043Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/14/1efe333c1e4d95b2e9b4bf5f370733234df594eac982d5c84c7af6b2322b/langchain_cohere-0.5.0-py3-none-any.whl", hash = "sha256:d8c3ad7b81d8240e6ee3e51c202f40d878484c15944f5774a3c233cf4fc7c95f", size = 42304, upload-time = "2025-11-04T14:02:38.107Z" }, +] + [[package]] name = "langchain-community" version = "0.4.1" @@ -1177,7 +1377,7 @@ wheels = [ [[package]] name = "langchain-core" -version = "1.2.9" +version = "1.2.16" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, @@ -1189,9 +1389,9 @@ dependencies = [ { name = "typing-extensions" }, { name = "uuid-utils" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/85/f501592b5d76b27a198f1102bafe365151a0a6f69444122fad6d10e6f4bf/langchain_core-1.2.9.tar.gz", hash = "sha256:a3768febc762307241d153b0f8bc58fd4b70c0ff077fda3274606741fca3f5a7", size = 815900, upload-time = "2026-02-05T14:21:43.942Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/a7/4c992456dae89a8704afec03e3c2a0149ccc5f29c1cbdd5f4aa77628e921/langchain_core-1.2.16.tar.gz", hash = "sha256:055a4bfe7d62f4ac45ed49fd759ee2e6bdd15abf998fbeea695fda5da2de6413", size = 835286, upload-time = "2026-02-25T16:27:30.551Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/94/46/77846a98913e444d0d564070a9056bd999daada52bd099dc1e8812272810/langchain_core-1.2.9-py3-none-any.whl", hash = "sha256:7e5ecba5ed7a65852e8d5288e9ceeba05340fa9baf32baf672818b497bbaea8f", size = 496296, upload-time = "2026-02-05T14:21:42.816Z" }, + { url = "https://files.pythonhosted.org/packages/2d/a1/57d5feaa11dc2ebb40f3bc3d7bf4294b6703e152e56edea9d4c622475a6a/langchain_core-1.2.16-py3-none-any.whl", hash = "sha256:2768add9aa97232a7712580f678e0ba045ee1036c71fe471355be0434fcb6e30", size = 502219, upload-time = "2026-02-25T16:27:29.379Z" }, ] [[package]] @@ -1232,6 +1432,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b6/d9/3adf09ff844a6d5c9dad9fe9ad6a032b706a1184eae71caa4c89bb470cbd/langchain_google_vertexai-3.2.2-py3-none-any.whl", hash = "sha256:aee8ea79f5aa19da74058e3905c78e0d3b882d5bc9eaf8549d92c13a5c458fda", size = 113381, upload-time = "2026-01-30T18:29:12.13Z" }, ] +[[package]] +name = "langchain-groq" +version = "1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "groq" }, + { name = "langchain-core" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/d9/bbaa43598fcaffb669c5aea4088d92c77a426c46d25a013c21c979772a54/langchain_groq-1.1.2.tar.gz", hash = "sha256:67d1d752fb6590be517735947ec49b4ab9ed9191c7cca79f105d227775c67ae5", size = 178337, upload-time = "2026-02-02T15:57:29.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/11/71a35db3ed8ac2c7129eb69f0d590e4961be67ac84b6c470fc097d0dd7c8/langchain_groq-1.1.2-py3-none-any.whl", hash = "sha256:1f59f12233e8e6280c968bca6c40a7e5434e971e9a5387ad23c4c64ec776de10", size = 19450, upload-time = "2026-02-02T15:57:28.6Z" }, +] + +[[package]] +name = "langchain-huggingface" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "langchain-core" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/2c/4fddeb3387baa05b6a95870ad514f649cafb46e0c0ef9caf949d974e55d2/langchain_huggingface-1.2.0.tar.gz", hash = "sha256:18a2d79955271261fb245b233fea6aa29625576e841f2b4f5bee41e51cc70949", size = 255602, upload-time = "2025-12-12T22:19:51.021Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/ce/502157ef7390a31cc67e5873ad66e737a25d1d33fcf6936e5c9a0a451409/langchain_huggingface-1.2.0-py3-none-any.whl", hash = "sha256:0ff6a17d3eb36ce2304f446e3285c74b59358703e8f7916c15bfcf9ec7b57bf1", size = 30671, upload-time = "2025-12-12T22:19:50.023Z" }, +] + [[package]] name = "langchain-mcp-adapters" version = "0.2.1" @@ -1246,6 +1473,22 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/81/b2479eb26861ab36be851026d004b2d391d789b7856e44c272b12828ece0/langchain_mcp_adapters-0.2.1-py3-none-any.whl", hash = "sha256:9f96ad4c64230f6757297fec06fde19d772c99dbdfbca987f7b7cfd51ff77240", size = 22708, upload-time = "2025-12-09T16:28:37.877Z" }, ] +[[package]] +name = "langchain-mistralai" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "langchain-core" }, + { name = "pydantic" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/07/cdfcfed8dc680634ae470868aecb9ac48f953302b13c0bb119f6ee96e1be/langchain_mistralai-1.1.1.tar.gz", hash = "sha256:2430dd6c5e714252ce58bdf9453da4e1f2c694e239dde7e9c4d488a6d1ef2368", size = 143032, upload-time = "2025-12-12T22:11:54.594Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/96/67e029665e9c348a2f17d1a681dc139631a6d8241b7a8d8e6ee69ff70a4b/langchain_mistralai-1.1.1-py3-none-any.whl", hash = "sha256:47839fc69c879bad4ff60133f238c15574416c2dcd850121621a7e9de45800c1", size = 19439, upload-time = "2025-12-12T22:11:53.546Z" }, +] + [[package]] name = "langchain-model-profiles" version = "0.0.5" @@ -2535,6 +2778,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/b0/2d823f6e77ebe560f4e397d078487e8d52c1516b331e3521bc75db4272ca/ruff-0.15.0-py3-none-win_arm64.whl", hash = "sha256:c480d632cc0ca3f0727acac8b7d053542d9e114a462a145d0b00e7cd658c515a", size = 10865753, upload-time = "2026-02-03T17:53:03.014Z" }, ] +[[package]] +name = "s3transfer" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "botocore" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/05/04/74127fc843314818edfa81b5540e26dd537353b123a4edc563109d8f17dd/s3transfer-0.16.0.tar.gz", hash = "sha256:8e990f13268025792229cd52fa10cb7163744bf56e719e0b9cb925ab79abf920", size = 153827, upload-time = "2025-12-01T02:30:59.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/51/727abb13f44c1fcf6d145979e1535a35794db0f6e450a0cb46aa24732fe2/s3transfer-0.16.0-py3-none-any.whl", hash = "sha256:18e25d66fed509e3868dc1572b3f427ff947dd2c56f844a5bf09481ad3f3b2fe", size = 86830, upload-time = "2025-12-01T02:30:57.729Z" }, +] + [[package]] name = "setuptools" version = "81.0.0" @@ -2692,6 +2947,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload-time = "2025-10-06T20:22:18.036Z" }, ] +[[package]] +name = "tokenizers" +version = "0.22.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/92/97/5dbfabf04c7e348e655e907ed27913e03db0923abb5dfdd120d7b25630e1/tokenizers-0.22.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:544dd704ae7238755d790de45ba8da072e9af3eea688f698b137915ae959281c", size = 3100275, upload-time = "2026-01-05T10:41:02.158Z" }, + { url = "https://files.pythonhosted.org/packages/2e/47/174dca0502ef88b28f1c9e06b73ce33500eedfac7a7692108aec220464e7/tokenizers-0.22.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:1e418a55456beedca4621dbab65a318981467a2b188e982a23e117f115ce5001", size = 2981472, upload-time = "2026-01-05T10:41:00.276Z" }, + { url = "https://files.pythonhosted.org/packages/d6/84/7990e799f1309a8b87af6b948f31edaa12a3ed22d11b352eaf4f4b2e5753/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249487018adec45d6e3554c71d46eb39fa8ea67156c640f7513eb26f318cec7", size = 3290736, upload-time = "2026-01-05T10:40:32.165Z" }, + { url = "https://files.pythonhosted.org/packages/78/59/09d0d9ba94dcd5f4f1368d4858d24546b4bdc0231c2354aa31d6199f0399/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25b85325d0815e86e0bac263506dd114578953b7b53d7de09a6485e4a160a7dd", size = 3168835, upload-time = "2026-01-05T10:40:38.847Z" }, + { url = "https://files.pythonhosted.org/packages/47/50/b3ebb4243e7160bda8d34b731e54dd8ab8b133e50775872e7a434e524c28/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bfb88f22a209ff7b40a576d5324bf8286b519d7358663db21d6246fb17eea2d5", size = 3521673, upload-time = "2026-01-05T10:40:56.614Z" }, + { url = "https://files.pythonhosted.org/packages/e0/fa/89f4cb9e08df770b57adb96f8cbb7e22695a4cb6c2bd5f0c4f0ebcf33b66/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c774b1276f71e1ef716e5486f21e76333464f47bece56bbd554485982a9e03e", size = 3724818, upload-time = "2026-01-05T10:40:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/64/04/ca2363f0bfbe3b3d36e95bf67e56a4c88c8e3362b658e616d1ac185d47f2/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:df6c4265b289083bf710dff49bc51ef252f9d5be33a45ee2bed151114a56207b", size = 3379195, upload-time = "2026-01-05T10:40:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/2e/76/932be4b50ef6ccedf9d3c6639b056a967a86258c6d9200643f01269211ca/tokenizers-0.22.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:369cc9fc8cc10cb24143873a0d95438bb8ee257bb80c71989e3ee290e8d72c67", size = 3274982, upload-time = "2026-01-05T10:40:58.331Z" }, + { url = "https://files.pythonhosted.org/packages/1d/28/5f9f5a4cc211b69e89420980e483831bcc29dade307955cc9dc858a40f01/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:29c30b83d8dcd061078b05ae0cb94d3c710555fbb44861139f9f83dcca3dc3e4", size = 9478245, upload-time = "2026-01-05T10:41:04.053Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fb/66e2da4704d6aadebf8cb39f1d6d1957df667ab24cff2326b77cda0dcb85/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:37ae80a28c1d3265bb1f22464c856bd23c02a05bb211e56d0c5301a435be6c1a", size = 9560069, upload-time = "2026-01-05T10:45:10.673Z" }, + { url = "https://files.pythonhosted.org/packages/16/04/fed398b05caa87ce9b1a1bb5166645e38196081b225059a6edaff6440fac/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:791135ee325f2336f498590eb2f11dc5c295232f288e75c99a36c5dbce63088a", size = 9899263, upload-time = "2026-01-05T10:45:12.559Z" }, + { url = "https://files.pythonhosted.org/packages/05/a1/d62dfe7376beaaf1394917e0f8e93ee5f67fea8fcf4107501db35996586b/tokenizers-0.22.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38337540fbbddff8e999d59970f3c6f35a82de10053206a7562f1ea02d046fa5", size = 10033429, upload-time = "2026-01-05T10:45:14.333Z" }, + { url = "https://files.pythonhosted.org/packages/fd/18/a545c4ea42af3df6effd7d13d250ba77a0a86fb20393143bbb9a92e434d4/tokenizers-0.22.2-cp39-abi3-win32.whl", hash = "sha256:a6bf3f88c554a2b653af81f3204491c818ae2ac6fbc09e76ef4773351292bc92", size = 2502363, upload-time = "2026-01-05T10:45:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/65/71/0670843133a43d43070abeb1949abfdef12a86d490bea9cd9e18e37c5ff7/tokenizers-0.22.2-cp39-abi3-win_amd64.whl", hash = "sha256:c9ea31edff2968b44a88f97d784c2f16dc0729b8b143ed004699ebca91f05c48", size = 2747786, upload-time = "2026-01-05T10:45:18.411Z" }, + { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, +] + [[package]] name = "tqdm" version = "4.67.3" @@ -2763,6 +3044,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/1d/d9257dd49ff2ca23ea5f132edf1281a0c4f9de8a762b9ae399b670a59235/typer-0.21.1-py3-none-any.whl", hash = "sha256:7985e89081c636b88d172c2ee0cfe33c253160994d47bdfdc302defd7d1f1d01", size = 47381, upload-time = "2026-01-06T11:21:09.824Z" }, ] +[[package]] +name = "types-pyyaml" +version = "6.0.12.20250915" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/69/3c51b36d04da19b92f9e815be12753125bd8bc247ba0470a982e6979e71c/types_pyyaml-6.0.12.20250915.tar.gz", hash = "sha256:0f8b54a528c303f0e6f7165687dd33fafa81c807fcac23f632b63aa624ced1d3", size = 17522, upload-time = "2025-09-15T03:01:00.728Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/e0/1eed384f02555dde685fff1a1ac805c1c7dcb6dd019c916fe659b1c1f9ec/types_pyyaml-6.0.12.20250915-py3-none-any.whl", hash = "sha256:e7d4d9e064e89a3b3cae120b4990cd370874d2bf12fa5f46c97018dd5d3c9ab6", size = 20338, upload-time = "2025-09-15T03:00:59.218Z" }, +] + [[package]] name = "types-requests" version = "2.32.4.20260107" From f76487af197851d253786c15d35278d6d59d8ff6 Mon Sep 17 00:00:00 2001 From: Jean Silva Date: Sat, 28 Feb 2026 14:25:07 +0100 Subject: [PATCH 2/2] fix: changed the monkeypatch target - from agentic_framework.constants._create_model to agentic_framework.core.langgraph_agent._create_model in 4 test files --- agentic-framework/tests/test_core_agents.py | 4 ++-- agentic-framework/tests/test_developer_agent.py | 10 +++++----- .../tests/test_github_pr_reviewer_agent.py | 8 ++++---- .../tests/test_travel_coordinator_agent.py | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/agentic-framework/tests/test_core_agents.py b/agentic-framework/tests/test_core_agents.py index 89ebb9e..66427a7 100644 --- a/agentic-framework/tests/test_core_agents.py +++ b/agentic-framework/tests/test_core_agents.py @@ -12,7 +12,7 @@ async def ainvoke(self, payload, config): def test_chef_agent_prompt_and_mcp(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = ChefAgent(initial_mcp_tools=[]) @@ -24,7 +24,7 @@ def test_chef_agent_prompt_and_mcp(monkeypatch): def test_travel_and_news_prompts(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) travel = TravelAgent(initial_mcp_tools=[]) diff --git a/agentic-framework/tests/test_developer_agent.py b/agentic-framework/tests/test_developer_agent.py index 9cf68af..dc5ef89 100644 --- a/agentic-framework/tests/test_developer_agent.py +++ b/agentic-framework/tests/test_developer_agent.py @@ -10,7 +10,7 @@ async def ainvoke(self, payload, config): def test_developer_agent_system_prompt(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -25,7 +25,7 @@ def test_developer_agent_system_prompt(monkeypatch): def test_developer_agent_local_tools_count(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -46,7 +46,7 @@ def test_developer_agent_local_tools_count(monkeypatch): def test_developer_agent_tool_descriptions(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -64,7 +64,7 @@ def test_developer_agent_tool_descriptions(monkeypatch): def test_developer_agent_run(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) agent = DeveloperAgent(initial_mcp_tools=[]) @@ -74,7 +74,7 @@ def test_developer_agent_run(monkeypatch): def test_developer_agent_with_mcp_tools(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # Simulate MCP tools diff --git a/agentic-framework/tests/test_github_pr_reviewer_agent.py b/agentic-framework/tests/test_github_pr_reviewer_agent.py index c08b18b..4c0ae8e 100644 --- a/agentic-framework/tests/test_github_pr_reviewer_agent.py +++ b/agentic-framework/tests/test_github_pr_reviewer_agent.py @@ -26,7 +26,7 @@ async def ainvoke(self, payload: dict, config: dict) -> dict: def test_github_pr_reviewer_system_prompt(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -41,7 +41,7 @@ def test_github_pr_reviewer_system_prompt(monkeypatch: object) -> None: def test_github_pr_reviewer_tools_count(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -62,7 +62,7 @@ def test_github_pr_reviewer_tools_count(monkeypatch: object) -> None: def test_github_pr_reviewer_tool_descriptions(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) @@ -77,7 +77,7 @@ def test_github_pr_reviewer_tool_descriptions(monkeypatch: object) -> None: def test_github_pr_reviewer_run(monkeypatch: object) -> None: - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) # type: ignore[attr-defined] + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) # type: ignore[attr-defined] monkeypatch.setattr("agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph()) # type: ignore[attr-defined] agent = GitHubPRReviewerAgent(initial_mcp_tools=[]) diff --git a/agentic-framework/tests/test_travel_coordinator_agent.py b/agentic-framework/tests/test_travel_coordinator_agent.py index f222b2a..96e61e4 100644 --- a/agentic-framework/tests/test_travel_coordinator_agent.py +++ b/agentic-framework/tests/test_travel_coordinator_agent.py @@ -22,7 +22,7 @@ async def ainvoke(self, payload, config): def test_travel_coordinator_orchestrates_three_specialists(monkeypatch): calls: list[tuple[str, dict, dict]] = [] - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) def fake_create_agent(**kwargs): system_prompt = kwargs["system_prompt"] @@ -52,7 +52,7 @@ def fake_create_agent(**kwargs): def test_travel_coordinator_get_tools_aggregates_from_specialists(monkeypatch): - monkeypatch.setattr("agentic_framework.constants._create_model", lambda model, temp: object()) + monkeypatch.setattr("agentic_framework.core.langgraph_agent._create_model", lambda model, temp: object()) monkeypatch.setattr( "agentic_framework.core.langgraph_agent.create_agent", lambda **kwargs: DummyGraph("review", []),