91e75e620b
CI: cua-driver distro-compat matrix / debian:12 (glibc 2.36) (push) Has been cancelled
CI: SPDX Headers / Check SPDX headers (warn-only) (push) Has been cancelled
CD: Docs MCP Server / build (linux/amd64) (push) Has been cancelled
CD: Docs MCP Server / build (linux/arm64) (push) Has been cancelled
CD: Docs MCP Server / merge (push) Has been cancelled
CI: cua-driver distro-compat matrix / Resolve release version (push) Has been cancelled
CI: cua-driver distro-compat matrix / fedora:41 (glibc 2.40) (push) Has been cancelled
CI: cua-driver distro-compat matrix / rockylinux:9 (glibc 2.34) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:22.04 (glibc 2.35) (push) Has been cancelled
CI: cua-driver distro-compat matrix / ubuntu:24.04 (glibc 2.39) (push) Has been cancelled
CI: cua-driver distro-compat matrix / Distro compat summary (push) Has been cancelled
CI: Rust Linux unit / Rust Linux unit and compile (push) Has been cancelled
CI: Rust Windows unit / Rust Windows unit and compile (push) Has been cancelled
CI: Nix Linux Rust source / Nix / compositor build (push) Has been cancelled
CI: Nix Linux Rust source / Nix / driver package (push) Has been cancelled
CI: Nix Linux Rust source / Nix / Rust unit tests (push) Has been cancelled
100 lines
3.5 KiB
Python
100 lines
3.5 KiB
Python
"""
|
|
Yutori adapter for litellm - routes yutori/ prefixed models to the Yutori API.
|
|
"""
|
|
|
|
import os
|
|
from typing import Any, AsyncIterator, Iterator
|
|
|
|
from litellm import acompletion, completion
|
|
from litellm.llms.custom_llm import CustomLLM
|
|
from litellm.types.utils import GenericStreamingChunk, ModelResponse
|
|
|
|
YUTORI_API_BASE = "https://api.yutori.com/v1"
|
|
|
|
|
|
class YutoriAdapter(CustomLLM):
|
|
def __init__(self, base_url: str | None = None, api_key: str | None = None, **_: Any):
|
|
super().__init__()
|
|
self.base_url = base_url or os.environ.get("YUTORI_API_BASE") or YUTORI_API_BASE
|
|
self.api_key = api_key or os.environ.get("YUTORI_API_KEY")
|
|
|
|
def _normalize_model(self, model: str) -> str:
|
|
"""Strip the yutori/ prefix to get the bare model name."""
|
|
if model.startswith("yutori/"):
|
|
return model[len("yutori/") :]
|
|
return model
|
|
|
|
def _resolve_api_key(self, kwargs: dict | None = None) -> str:
|
|
"""Resolve the Yutori API key, raising a clear error if missing."""
|
|
resolved = (kwargs.get("api_key") if kwargs else None) or self.api_key
|
|
if not resolved:
|
|
raise ValueError(
|
|
"No Yutori API key provided. "
|
|
"Please either set the YUTORI_API_KEY environment variable "
|
|
"or pass api_key to ComputerAgent()."
|
|
)
|
|
return resolved
|
|
|
|
def _build_params(self, kwargs: dict) -> dict:
|
|
"""Build parameters for the inner litellm call."""
|
|
model = self._normalize_model(kwargs.get("model", ""))
|
|
api_key = self._resolve_api_key(kwargs)
|
|
|
|
extra_headers = {}
|
|
if "extra_headers" in kwargs:
|
|
extra_headers.update(kwargs.pop("extra_headers"))
|
|
extra_headers["Authorization"] = f"Bearer {api_key}"
|
|
|
|
params = {
|
|
"model": f"openai/{model}",
|
|
"messages": kwargs.get("messages", []),
|
|
"api_base": self.base_url,
|
|
"api_key": api_key,
|
|
"extra_headers": extra_headers,
|
|
"stream": False,
|
|
}
|
|
|
|
# Forward tools if provided
|
|
if "tools" in kwargs:
|
|
params["tools"] = kwargs["tools"]
|
|
if "tool_choice" in kwargs:
|
|
params["tool_choice"] = kwargs["tool_choice"]
|
|
|
|
# Forward optional generation params
|
|
for key in (
|
|
"temperature",
|
|
"top_p",
|
|
"max_completion_tokens",
|
|
"max_tokens",
|
|
"response_format",
|
|
):
|
|
if key in kwargs:
|
|
params[key] = kwargs[key]
|
|
|
|
if "optional_params" in kwargs:
|
|
protected_keys = {"api_key", "extra_headers", "model", "api_base", "stream"}
|
|
filtered = {
|
|
k: v for k, v in kwargs["optional_params"].items() if k not in protected_keys
|
|
}
|
|
params.update(filtered)
|
|
|
|
if "headers" in kwargs:
|
|
params["headers"] = kwargs["headers"]
|
|
|
|
return params
|
|
|
|
def completion(self, *args, **kwargs) -> ModelResponse:
|
|
params = self._build_params(kwargs)
|
|
return completion(**params) # type: ignore
|
|
|
|
async def acompletion(self, *args, **kwargs) -> ModelResponse:
|
|
params = self._build_params(kwargs)
|
|
response = await acompletion(**params) # type: ignore
|
|
return response
|
|
|
|
def streaming(self, *args, **kwargs) -> Iterator[GenericStreamingChunk]:
|
|
raise NotImplementedError("Yutori n1 does not support streaming.")
|
|
|
|
async def astreaming(self, *args, **kwargs) -> AsyncIterator[GenericStreamingChunk]:
|
|
raise NotImplementedError("Yutori n1 does not support streaming.")
|