feat: Add OpenAI provider support for embeddings and generation

Adds OpenAI provider to the unified provider architecture (ADR-015),
supporting:
- OpenAI API (api.openai.com)
- GitHub Models API (models.github.ai/inference)
- OpenAI-compatible endpoints (Fireworks, Together, etc.)

Features:
- Embedding support with text-embedding-3-small/large models
- Text generation via chat completions API
- Automatic retry with exponential backoff for rate limits
- Provider auto-detection in registry (priority after Bedrock)

Environment variables:
- OPENAI_API_KEY: API key (required)
- OPENAI_BASE_URL: Base URL override (optional)
- OPENAI_EMBEDDING_MODEL: Embedding model (default: text-embedding-3-small)
- OPENAI_GENERATION_MODEL: Generation model (default: gpt-4o-mini)

Also adds:
- Integration tests for RAG pipeline with MCP sampling
- MCP client sampling support for integration tests
- Ground truth Q&A pairs for Nextcloud User Manual

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2025-11-23 00:33:32 +01:00
co-authored by Claude
parent 959cb8b21a
commit 208365cd3d
14 changed files with 1176 additions and 21 deletions
+26 -4
View File
@@ -3,8 +3,8 @@
DEPRECATED: This module is maintained for backward compatibility with RAG evaluation tests.
New code should use nextcloud_mcp_server.providers directly.
Supports Ollama (local), Anthropic (cloud), and Bedrock (AWS) providers for both ground truth
generation and evaluation.
Supports Ollama (local), Anthropic (cloud), Bedrock (AWS), and OpenAI (cloud) providers
for both ground truth generation and evaluation.
"""
import os
@@ -13,6 +13,7 @@ from nextcloud_mcp_server.providers import (
AnthropicProvider,
BedrockProvider,
OllamaProvider,
OpenAIProvider,
Provider,
)
@@ -25,11 +26,14 @@ def create_llm_provider(
anthropic_model: str | None = None,
bedrock_region: str | None = None,
bedrock_model: str | None = None,
openai_api_key: str | None = None,
openai_base_url: str | None = None,
openai_model: str | None = None,
) -> Provider:
"""Create an LLM provider from environment variables or arguments.
Args:
provider: Provider type ('ollama', 'anthropic', or 'bedrock').
provider: Provider type ('ollama', 'anthropic', 'bedrock', or 'openai').
Defaults to RAG_EVAL_PROVIDER env var or 'ollama'
ollama_base_url: Ollama base URL. Defaults to RAG_EVAL_OLLAMA_BASE_URL or 'http://localhost:11434'
ollama_model: Ollama model. Defaults to RAG_EVAL_OLLAMA_MODEL or 'llama3.2:1b'
@@ -38,6 +42,9 @@ def create_llm_provider(
bedrock_region: AWS region. Defaults to RAG_EVAL_BEDROCK_REGION or AWS_REGION env var
bedrock_model: Bedrock model ID. Defaults to RAG_EVAL_BEDROCK_MODEL or
'anthropic.claude-3-sonnet-20240229-v1:0'
openai_api_key: OpenAI API key. Defaults to OPENAI_API_KEY env var
openai_base_url: OpenAI base URL. Defaults to OPENAI_BASE_URL (for GitHub Models API)
openai_model: OpenAI model. Defaults to OPENAI_GENERATION_MODEL or 'gpt-4o-mini'
Returns:
Provider instance
@@ -83,7 +90,22 @@ def create_llm_provider(
region_name=region, embedding_model=None, generation_model=model
)
elif provider == "openai":
api_key = openai_api_key or os.environ.get("OPENAI_API_KEY")
if not api_key:
raise ValueError(
"OpenAI API key required. Set OPENAI_API_KEY environment variable."
)
base_url = openai_base_url or os.environ.get("OPENAI_BASE_URL")
model = openai_model or os.environ.get("OPENAI_GENERATION_MODEL", "gpt-4o-mini")
return OpenAIProvider(
api_key=api_key,
base_url=base_url,
embedding_model=None,
generation_model=model,
)
else:
raise ValueError(
f"Invalid provider: {provider}. Must be 'ollama', 'anthropic', or 'bedrock'."
f"Invalid provider: {provider}. Must be 'ollama', 'anthropic', 'bedrock', or 'openai'."
)