Files
wehub-resource-sync 97e91a83f3
Ruff / Ruff (push) Has been cancelled
Test / Core Tests (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.10) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.11) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.12) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.13) (push) Has been cancelled
Test / Offline Coverage Tests (Python 3.9) (push) Has been cancelled
Test / Full Coverage (Python 3.11) (push) Has been cancelled
Test / Core Provider Tests (OpenAI) (push) Has been cancelled
Test / Core Provider Tests (Anthropic) (push) Has been cancelled
Test / Core Provider Tests (Google) (push) Has been cancelled
Test / Core Provider Tests (Other) (push) Has been cancelled
Test / Anthropic Tests (push) Has been cancelled
Test / Gemini Tests (push) Has been cancelled
Test / Google GenAI Tests (push) Has been cancelled
Test / Vertex AI Tests (push) Has been cancelled
Test / OpenAI Tests (push) Has been cancelled
Test / Writer Tests (push) Has been cancelled
Test / Auto Client Tests (push) Has been cancelled
ty / type-check (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:36:38 +08:00

148 lines
4.7 KiB
Python

# type: ignore[all]
from __future__ import annotations
from typing import Any
from textwrap import dedent
from instructor.v2.core.mode import Mode
from instructor.v2.core.providers import Provider, provider_from_mode
from jinja2.sandbox import SandboxedEnvironment
def apply_template(text: str, context: dict[str, Any]) -> str:
"""Apply Jinja2 template to the given text."""
return dedent(SandboxedEnvironment().from_string(text).render(**context))
def process_message(
message: dict[str, Any], context: dict[str, Any], provider: Provider
) -> dict[str, Any]:
"""Process a single message, applying templates to its content."""
if provider == Provider.GENAI:
from instructor.v2.providers.genai.templating import (
process_message as process_genai_message,
)
return process_genai_message(message, context, apply_template)
# VertexAI Support
if (
hasattr(message, "parts")
and isinstance(message.parts, list)
and len(message.parts) > 0
and not isinstance(message.parts[0], str)
):
from instructor.v2.providers.vertexai.templating import (
process_message as process_vertexai_message,
)
return process_vertexai_message(message, context, apply_template)
# OpenAI format
if isinstance(message.get("content"), str):
from instructor.v2.providers.openai.templating import (
process_message as process_openai_message,
)
return process_openai_message(message, context, apply_template)
# Anthropic format
if isinstance(message.get("content"), list):
from instructor.v2.providers.anthropic.templating import (
process_message as process_anthropic_message,
)
return process_anthropic_message(message, context, apply_template)
# Gemini Support
if isinstance(message.get("parts"), list):
from instructor.v2.providers.gemini.templating import (
process_message as process_gemini_message,
)
return process_gemini_message(message, context, apply_template)
# Cohere format
if isinstance(message.get("message"), str):
from instructor.v2.providers.cohere.templating import (
process_message as process_cohere_message,
)
return process_cohere_message(message, context, apply_template)
return message
def _copy_message_for_templating(message: Any) -> Any:
if not isinstance(message, dict):
return message
copied_message = message.copy()
for field in ("content", "parts"):
parts = copied_message.get(field)
if isinstance(parts, list):
copied_message[field] = [
part.copy() if isinstance(part, dict) else part for part in parts
]
return copied_message
def handle_templating(
kwargs: dict[str, Any],
mode: Mode, # noqa: ARG001
provider: Provider | dict[str, Any] | None = None,
context: dict[str, Any] | None = None,
) -> dict[str, Any]:
"""
Handle templating for messages using the provided context.
This function processes messages, applying Jinja2 templating to their content
using the provided context. It supports various message formats including
OpenAI, Anthropic, Cohere, VertexAI, and Gemini.
Args:
kwargs (Dict[str, Any]): Keyword arguments being passed to the create method.
context (Dict[str, Any] | None, optional): Variables to use in templating. Defaults to None.
Returns:
Dict[str, Any]: The processed kwargs with templated content.
Raises:
ValueError: If no recognized message format is found in kwargs.
"""
if context is None and isinstance(provider, dict):
context = provider
provider = None
if not context:
return kwargs
if not isinstance(provider, Provider):
provider = provider_from_mode(mode, Provider.OPENAI)
new_kwargs = kwargs.copy()
# Handle Cohere's message field
if "message" in new_kwargs:
new_kwargs["message"] = apply_template(new_kwargs["message"], context)
new_kwargs["chat_history"] = [
process_message(_copy_message_for_templating(message), context, provider)
for message in new_kwargs.get("chat_history", [])
]
return new_kwargs
if isinstance(new_kwargs, list):
return new_kwargs
message_key = "messages" if new_kwargs.get("messages") else "contents"
messages = new_kwargs.get(message_key)
if not messages:
return new_kwargs
new_kwargs[message_key] = [
process_message(_copy_message_for_templating(message), context, provider)
for message in messages
]
return new_kwargs