Source code for oas2mcp.agent.base

"""Thin LangChain v1 agent factory helpers for ``oas2mcp``.

Purpose:
    Provide shared helpers for constructing LangChain v1 agents and the default
    OpenAI-backed chat model used by ``oas2mcp`` workflows.

Design:
    - Keep the wrapper intentionally thin.
    - Centralize common defaults such as runtime context schema and state schema.
    - Centralize default model construction, reasoning configuration, and
      environment loading.
    - Leave workflow-specific prompts, middleware, and structured outputs to
      submodules like ``summarizer`` and ``enhancer``.

Examples:
    .. code-block:: python

        model = build_default_chat_model()
        agent = build_base_agent(
            model=model,
            response_format=MyOutputModel,
        )
"""

from __future__ import annotations

import os
from pathlib import Path
from typing import Any

from dotenv import load_dotenv
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

from oas2mcp.agent.runtime import Oas2McpRuntimeContext
from oas2mcp.agent.state import OpenApiEnhancementState

[docs] DEFAULT_MODEL_NAME = "gpt-5.1"
[docs] DEFAULT_REASONING_EFFORT = "high"
[docs] def load_project_env() -> None: """Load likely project-local environment files. Args: None. Returns: None. Raises: None. """ load_dotenv() cwd_env = Path.cwd() / ".env" if cwd_env.exists(): load_dotenv(cwd_env, override=False)
[docs] def require_openai_api_key() -> str: """Return the OpenAI API key from the environment. Args: None. Returns: str: The resolved API key. Raises: RuntimeError: If the key is not available. """ load_project_env() api_key = os.getenv("OPENAI_API_KEY") if not api_key: raise RuntimeError( "OPENAI_API_KEY is not set. Put it in your shell environment or .env." ) return api_key
[docs] def build_default_chat_model( *, model_name: str = DEFAULT_MODEL_NAME, reasoning_effort: str = DEFAULT_REASONING_EFFORT, api_key: str | None = None, **kwargs: Any, ) -> ChatOpenAI: """Build the default OpenAI chat model. Args: model_name: The OpenAI model name. reasoning_effort: The reasoning effort to request. api_key: Optional OpenAI API key. **kwargs: Extra keyword arguments forwarded to ``ChatOpenAI``. Returns: ChatOpenAI: Configured chat model. Raises: RuntimeError: If no API key is available. """ resolved_api_key = api_key or require_openai_api_key() return ChatOpenAI( model=model_name, api_key=resolved_api_key, reasoning={"effort": reasoning_effort}, **kwargs, )
[docs] def build_base_agent( *, response_format: Any, tools: list[Any] | None = None, middleware: list[Any] | None = None, system_prompt: str | None = None, model: Any | None = None, model_name: str = DEFAULT_MODEL_NAME, reasoning_effort: str = DEFAULT_REASONING_EFFORT, model_kwargs: dict[str, Any] | None = None, ): """Build a stateful LangChain v1 agent for ``oas2mcp``. Args: response_format: Structured output schema or strategy. tools: Optional tools. middleware: Optional middleware stack. system_prompt: Optional base system prompt. model: Optional model instance or model identifier. model_name: Default model name when ``model`` is omitted. reasoning_effort: Default reasoning effort when ``model`` is omitted. model_kwargs: Extra kwargs used only when building the default model. Returns: The constructed LangChain agent runnable. Raises: RuntimeError: If the default model is used and no API key is available. """ resolved_model = model or build_default_chat_model( model_name=model_name, reasoning_effort=reasoning_effort, **(model_kwargs or {}), ) return create_agent( model=resolved_model, tools=tools or [], middleware=middleware or [], system_prompt=system_prompt or "", response_format=response_format, context_schema=Oas2McpRuntimeContext, state_schema=OpenApiEnhancementState, )