mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-27 06:13:07 +00:00
Merge 27f8047904 into 1fcbb0355e
This commit is contained in:
commit
a35f53a3cf
13 changed files with 3093 additions and 4 deletions
|
|
@ -109,6 +109,7 @@ GATEWAY_PATH_PREFIXES: tuple[str, ...] = (
|
|||
"/vllm/",
|
||||
"/mistral/",
|
||||
"/typesafe/",
|
||||
"/eu_jev/",
|
||||
"/openrouter/",
|
||||
"/nvidia_nim/",
|
||||
"/groq/",
|
||||
|
|
|
|||
|
|
@ -72264,6 +72264,28 @@
|
|||
"source": "https://docs.typesafe.ai/models",
|
||||
"supports_box_questions": true
|
||||
},
|
||||
"eu_jev/eu-jeff-1.0.0": {
|
||||
"input_cost_per_token": 4.15e-08,
|
||||
"litellm_provider": "eu_jev",
|
||||
"max_input_tokens": 32768,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://eu-jev.com/docs",
|
||||
"supported_endpoints": [
|
||||
"/v1/systemone"
|
||||
]
|
||||
},
|
||||
"eu_jev/eu-jeff-latest": {
|
||||
"input_cost_per_token": 4.15e-08,
|
||||
"litellm_provider": "eu_jev",
|
||||
"max_input_tokens": 32768,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://eu-jev.com/docs",
|
||||
"supported_endpoints": [
|
||||
"/v1/systemone"
|
||||
]
|
||||
},
|
||||
"wandb/deepseek-ai/DeepSeek-V4.1-Flash": {
|
||||
"cache_read_input_token_cost": 3e-08,
|
||||
"input_cost_per_token": 2e-07,
|
||||
|
|
|
|||
|
|
@ -233,6 +233,7 @@ LAZY_FEATURES: Final[tuple[LazyFeature, ...]] = (
|
|||
"/tinyfish/",
|
||||
"/transcribe",
|
||||
"/typesafe/",
|
||||
"/eu_jev/",
|
||||
"/laya/",
|
||||
"/bespoke/",
|
||||
"/openrouter/",
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -411,6 +411,7 @@ class LiteLLMRoutes(enum.Enum):
|
|||
"/vllm",
|
||||
"/mistral",
|
||||
"/typesafe",
|
||||
"/eu_jev",
|
||||
"/laya",
|
||||
"/bespoke",
|
||||
"/openrouter",
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ from litellm.proxy.common_request_processing import (
|
|||
model_deployments_support_stream_options,
|
||||
open_sse_before_first_byte,
|
||||
)
|
||||
from litellm.proxy.common_utils.custom_openapi_spec import inline_request_body
|
||||
from litellm.proxy.common_utils.http_parsing_utils import ( # noqa: F401 # legacy module exports
|
||||
_read_request_body, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
|
||||
_safe_get_request_headers, # pyright: ignore[reportPrivateUsage,reportUnusedImport] # backwards-compatible package export
|
||||
|
|
@ -123,6 +124,7 @@ from litellm.proxy.vector_store_endpoints.utils import (
|
|||
is_allowed_to_call_vector_store_endpoint,
|
||||
)
|
||||
from litellm.secret_managers.main import get_secret_str, normalize_nonempty_secret_str, str_to_bool
|
||||
from litellm.types.passthrough_endpoints.eu_jev import EuJevDecisionRequest, EuJevDecisionResponse
|
||||
from litellm.types.passthrough_endpoints.pass_through_endpoints import (
|
||||
LITELLM_PASS_THROUGH_CUSTOM_BODY_STATE_KEY,
|
||||
LITELLM_PASS_THROUGH_DEPLOYMENT_MODEL_INFO_STATE_KEY,
|
||||
|
|
@ -691,6 +693,81 @@ async def typesafe_proxy_route(
|
|||
return await endpoint_func(request, fastapi_response, user_api_key_dict)
|
||||
|
||||
|
||||
_EU_JEV_DECISION_REQUEST_BODY: Final = inline_request_body(
|
||||
EuJevDecisionRequest,
|
||||
{
|
||||
"model": "eu-jeff-latest",
|
||||
"state": "I was charged twice. Can I get a refund?",
|
||||
"questions": {
|
||||
"team": {
|
||||
"type": "choice",
|
||||
"instructions": "Which team should handle this?",
|
||||
"criteria": {"billing": "Payments, invoices, and refunds", "support": "Technical issues and bugs"},
|
||||
},
|
||||
"is_refund_request": {"type": "noul", "instructions": "Is the customer asking for a refund?"},
|
||||
"frustration": {
|
||||
"type": "score",
|
||||
"instructions": "How frustrated is the customer?",
|
||||
"criteria": ["calm", "mildly annoyed", "angry"],
|
||||
},
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.api_route(
|
||||
"/eu_jev/{endpoint:path}",
|
||||
methods=["GET", "POST", "PUT", "DELETE", "PATCH"],
|
||||
tags=["eu/jev Pass-through", "pass-through"],
|
||||
responses={200: {"model": EuJevDecisionResponse}},
|
||||
openapi_extra={"requestBody": _EU_JEV_DECISION_REQUEST_BODY},
|
||||
)
|
||||
async def eu_jev_proxy_route(
|
||||
endpoint: str,
|
||||
request: Request,
|
||||
fastapi_response: Response,
|
||||
user_api_key_dict: Annotated[UserAPIKeyAuth, Depends(user_api_key_auth)],
|
||||
) -> Response:
|
||||
"""
|
||||
Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
|
||||
`POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
rejected with a 400.
|
||||
|
||||
[Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
"""
|
||||
body: Final = TypeAdapter(dict[str, object]).validate_python(await read_request_body(request))
|
||||
if "custom_body" in body:
|
||||
raise HTTPException(status_code=400, detail="custom_body is not supported for eu_jev requests")
|
||||
if body.get("stream"):
|
||||
raise HTTPException(status_code=400, detail="Streaming is not supported for eu_jev requests")
|
||||
base_target_url: Final = get_secret_str("EU_JEV_API_BASE") or "https://eu-jev.com"
|
||||
encoded_endpoint: Final = httpx.URL(endpoint).path
|
||||
normalized_endpoint: Final = encoded_endpoint if encoded_endpoint.startswith("/") else f"/{encoded_endpoint}"
|
||||
base_url: Final = httpx.URL(base_target_url)
|
||||
updated_url: Final = base_url.copy_with(
|
||||
path=HttpPassThroughEndpointHelpers.join_base_and_endpoint_path(base_url, normalized_endpoint),
|
||||
)
|
||||
eu_jev_api_key: Final = passthrough_endpoint_router.get_credentials(
|
||||
custom_llm_provider="eu_jev",
|
||||
region_name=None,
|
||||
)
|
||||
endpoint_func: Final = create_pass_through_route(
|
||||
endpoint=endpoint,
|
||||
target=str(updated_url),
|
||||
custom_headers={
|
||||
"Authorization": f"Bearer {eu_jev_api_key}",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
custom_llm_provider="eu_jev",
|
||||
is_streaming_request=False,
|
||||
)
|
||||
return TypeAdapter(Response, config=ConfigDict(arbitrary_types_allowed=True)).validate_python(
|
||||
await endpoint_func(request, fastapi_response, user_api_key_dict)
|
||||
)
|
||||
|
||||
|
||||
@router.post(
|
||||
"/laya/v1/systemone",
|
||||
tags=["Laya Pass-through", "pass-through"],
|
||||
|
|
|
|||
|
|
@ -409,9 +409,9 @@ class HttpPassThroughEndpointHelpers(BasePassthroughUtils):
|
|||
@staticmethod
|
||||
def get_endpoint_type(url: str, custom_llm_provider: str | None = None) -> EndpointType:
|
||||
parsed_url: Final = urlparse(url)
|
||||
if custom_llm_provider in ("typesafe", "laya", "bespoke") and parsed_url.path.removesuffix("/").endswith(
|
||||
"/v1/systemone"
|
||||
):
|
||||
if custom_llm_provider in ("typesafe", "eu_jev", "laya", "bespoke") and parsed_url.path.removesuffix(
|
||||
"/"
|
||||
).endswith("/v1/systemone"):
|
||||
return EndpointType.DECISIONS
|
||||
if (
|
||||
("generateContent") in url
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ class PassThroughEndpointLogging:
|
|||
kwargs = transcribe_handler_result["kwargs"] # rebind-ok: elif-chain contract
|
||||
elif (
|
||||
self.is_typesafe_route(custom_llm_provider)
|
||||
or custom_llm_provider in ("laya", "bespoke")
|
||||
or custom_llm_provider in ("eu_jev", "laya", "bespoke")
|
||||
or self.is_openrouter_decisions_route(url_route, custom_llm_provider)
|
||||
):
|
||||
from .llm_provider_handlers.typesafe_passthrough_logging_handler import (
|
||||
|
|
|
|||
100
litellm/types/passthrough_endpoints/eu_jev.py
Normal file
100
litellm/types/passthrough_endpoints/eu_jev.py
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
from collections.abc import Mapping, Sequence
|
||||
from typing import Annotated, Literal, TypeAlias
|
||||
|
||||
from pydantic import ConfigDict, Field
|
||||
|
||||
from litellm.types.decisions import ChoiceAnswer, DecisionsJSON, NoulAnswer, NoulCriteria, ScoreAnswer
|
||||
from litellm.types.llms.base import LiteLLMPydanticObjectBase
|
||||
|
||||
EuJevEntry: TypeAlias = Annotated[
|
||||
DecisionsJSON | None,
|
||||
Field(description="Free text, or a JSON object, array or null that eu/jev serializes to text before inference"),
|
||||
]
|
||||
|
||||
|
||||
class EuJevChoiceQuestion(LiteLLMPydanticObjectBase):
|
||||
type: Literal["choice"]
|
||||
instructions: EuJevEntry
|
||||
criteria: Annotated[
|
||||
Mapping[str, EuJevEntry],
|
||||
Field(
|
||||
min_length=2,
|
||||
max_length=64,
|
||||
description="Two to 64 options, option name to description. A null description uses the option name",
|
||||
),
|
||||
]
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
class EuJevNoulQuestion(LiteLLMPydanticObjectBase):
|
||||
type: Literal["noul"]
|
||||
instructions: EuJevEntry
|
||||
criteria: Annotated[NoulCriteria | None, Field(description="Optional descriptions of what true and false mean")] = (
|
||||
None
|
||||
)
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
class EuJevScoreQuestion(LiteLLMPydanticObjectBase):
|
||||
type: Literal["score"]
|
||||
instructions: EuJevEntry
|
||||
criteria: Annotated[
|
||||
Sequence[EuJevEntry],
|
||||
Field(min_length=2, max_length=10, description="Two to 10 level descriptions, ordered from low to high"),
|
||||
]
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
EuJevQuestion: TypeAlias = Annotated[
|
||||
EuJevChoiceQuestion | EuJevNoulQuestion | EuJevScoreQuestion,
|
||||
Field(discriminator="type"),
|
||||
]
|
||||
|
||||
|
||||
class EuJevDecisionRequest(LiteLLMPydanticObjectBase):
|
||||
model: Annotated[str, Field(description="eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it")] = (
|
||||
"eu-jeff-latest"
|
||||
)
|
||||
state: Annotated[
|
||||
Annotated[str, Field(min_length=1, max_length=100_000)] | Mapping[str, object] | Sequence[object],
|
||||
Field(description="The content to evaluate, a string of up to 100,000 characters or a JSON object or array"),
|
||||
]
|
||||
questions: Annotated[
|
||||
Mapping[Annotated[str, Field(min_length=1, max_length=80)], EuJevQuestion],
|
||||
Field(min_length=1, max_length=8, description="One to eight questions, keyed by names of up to 80 characters"),
|
||||
]
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
EuJevAnswer: TypeAlias = Annotated[ChoiceAnswer | NoulAnswer | ScoreAnswer, Field(discriminator="type")]
|
||||
|
||||
|
||||
class EuJevUsage(LiteLLMPydanticObjectBase):
|
||||
input_tokens: Annotated[int, Field(ge=0)]
|
||||
output_tokens: Annotated[int, Field(ge=0)]
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
class EuJevMeta(LiteLLMPydanticObjectBase):
|
||||
request_id: str
|
||||
mode: Literal["live"]
|
||||
latency_ms: Annotated[
|
||||
int, Field(description="Server-side time for token quoting, credit reservation and inference")
|
||||
]
|
||||
cost_eur: Annotated[str | None, Field(description="The exact charge in euros, on authenticated requests")] = None
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
||||
|
||||
class EuJevDecisionResponse(LiteLLMPydanticObjectBase):
|
||||
model: Annotated[str, Field(description="The release that answered, such as eu-jeff-1.0.0")]
|
||||
answers: Annotated[Mapping[str, EuJevAnswer], Field(description="One answer per question, under the same names")]
|
||||
usage: EuJevUsage
|
||||
meta: EuJevMeta
|
||||
|
||||
model_config = ConfigDict(frozen=True)
|
||||
|
|
@ -72264,6 +72264,28 @@
|
|||
"source": "https://docs.typesafe.ai/models",
|
||||
"supports_box_questions": true
|
||||
},
|
||||
"eu_jev/eu-jeff-1.0.0": {
|
||||
"input_cost_per_token": 4.15e-08,
|
||||
"litellm_provider": "eu_jev",
|
||||
"max_input_tokens": 32768,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://eu-jev.com/docs",
|
||||
"supported_endpoints": [
|
||||
"/v1/systemone"
|
||||
]
|
||||
},
|
||||
"eu_jev/eu-jeff-latest": {
|
||||
"input_cost_per_token": 4.15e-08,
|
||||
"litellm_provider": "eu_jev",
|
||||
"max_input_tokens": 32768,
|
||||
"mode": "evaluation",
|
||||
"output_cost_per_token": 0.0,
|
||||
"source": "https://eu-jev.com/docs",
|
||||
"supported_endpoints": [
|
||||
"/v1/systemone"
|
||||
]
|
||||
},
|
||||
"wandb/deepseek-ai/DeepSeek-V4.1-Flash": {
|
||||
"cache_read_input_token_cost": 3e-08,
|
||||
"input_cost_per_token": 2e-07,
|
||||
|
|
|
|||
|
|
@ -366,3 +366,44 @@ def test_success_handler_skips_typesafe_pricing_for_non_decisions_openrouter_rou
|
|||
assert normalized["standard_logging_response_object"] is None
|
||||
assert "combined_usage_object" not in normalized["kwargs"]
|
||||
assert normalized["kwargs"].get("model") != "openrouter/typesafe/jev-1.13-20260917"
|
||||
|
||||
|
||||
def test_eu_jev_decision_is_priced_from_its_registry_row():
|
||||
model_cost: Final = litellm.model_cost["eu_jev/eu-jeff-1.0.0"]
|
||||
response = TypeSafePassthroughLoggingHandler.typesafe_passthrough_handler(
|
||||
httpx_response=_response(),
|
||||
response_body={"model": "eu-jeff-1.0.0", "usage": {"input_tokens": 64, "output_tokens": 0}},
|
||||
logging_obj=_logging_obj(),
|
||||
url_route="https://eu-jev.com/v1/systemone",
|
||||
result='{"answers": {}}',
|
||||
start_time=datetime.now(),
|
||||
end_time=datetime.now(),
|
||||
cache_hit=False,
|
||||
request_body={"model": "eu-jeff-latest"},
|
||||
custom_llm_provider="eu_jev",
|
||||
)
|
||||
|
||||
assert response["kwargs"]["model"] == "eu_jev/eu-jeff-1.0.0"
|
||||
assert response["kwargs"]["custom_llm_provider"] == "eu_jev"
|
||||
assert response["kwargs"]["response_cost"] == pytest.approx(64 * model_cost["input_cost_per_token"])
|
||||
assert response["kwargs"]["response_cost"] > 0
|
||||
assert response["kwargs"]["combined_usage_object"].prompt_tokens == 64
|
||||
assert response["kwargs"]["combined_usage_object"].completion_tokens == 0
|
||||
|
||||
|
||||
def test_success_handler_dispatches_eu_jev_to_the_shared_handler():
|
||||
normalized = PassThroughEndpointLogging().normalize_llm_passthrough_logging_payload(
|
||||
httpx_response=_response(),
|
||||
response_body={"model": "eu-jeff-1.0.0", "usage": {"input_tokens": 64, "output_tokens": 0}},
|
||||
request_body={"model": "eu-jeff-latest"},
|
||||
logging_obj=_logging_obj(),
|
||||
url_route="https://eu-jev.com/v1/systemone",
|
||||
result="{}",
|
||||
start_time=datetime.now(),
|
||||
end_time=datetime.now(),
|
||||
cache_hit=False,
|
||||
custom_llm_provider="eu_jev",
|
||||
)
|
||||
|
||||
assert normalized["kwargs"]["custom_llm_provider"] == "eu_jev"
|
||||
assert normalized["kwargs"]["model"] == "eu_jev/eu-jeff-1.0.0"
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import (
|
|||
bedrock_proxy_route,
|
||||
create_pass_through_route,
|
||||
cursor_proxy_route,
|
||||
eu_jev_proxy_route,
|
||||
fal_ai_proxy_route,
|
||||
get_azure_ai_search_index_from_endpoint,
|
||||
get_vertex_base_url,
|
||||
|
|
@ -8324,6 +8325,120 @@ class TestTypeSafePassthroughRoute:
|
|||
)
|
||||
|
||||
|
||||
class TestEuJevPassthroughRoute:
|
||||
@staticmethod
|
||||
def _request(body: object, query_params: Mapping[str, str] | None = None) -> MagicMock:
|
||||
request = MagicMock(spec=Request)
|
||||
request.method = "POST"
|
||||
request.query_params = query_params or {}
|
||||
request.json = AsyncMock(return_value=body)
|
||||
return request
|
||||
|
||||
@pytest.fixture
|
||||
def client(self, monkeypatch: pytest.MonkeyPatch) -> Iterator[TestClient]:
|
||||
from litellm.proxy.proxy_server import app
|
||||
|
||||
monkeypatch.setenv("EU_JEV_API_KEY", "eu-jev-test-key")
|
||||
monkeypatch.setenv("EU_JEV_API_BASE", "https://eu-jev.example/base")
|
||||
monkeypatch.delenv("SERVER_ROOT_PATH", raising=False)
|
||||
monkeypatch.setattr(litellm, "disable_aiohttp_transport", True)
|
||||
litellm.in_memory_llm_clients_cache.flush_cache()
|
||||
monkeypatch.setitem(app.dependency_overrides, user_api_key_auth, lambda: UserAPIKeyAuth(api_key="sk-virtual"))
|
||||
yield TestClient(app)
|
||||
|
||||
def test_forwards_a_decision_upstream_with_the_eu_jev_key(self, client: TestClient) -> None:
|
||||
body: Final = {"model": "eu-jeff-latest", "state": "x"}
|
||||
with respx.mock(assert_all_called=True) as upstream:
|
||||
route = upstream.post("https://eu-jev.example/base/v1/systemone").mock(
|
||||
return_value=httpx.Response(200, json={"id": "upstream_123"})
|
||||
)
|
||||
response = client.post("/eu_jev/v1/systemone", json=body)
|
||||
|
||||
assert (response.status_code, response.json()) == (200, {"id": "upstream_123"})
|
||||
sent: Final = route.calls.last.request
|
||||
assert sent.headers["authorization"] == "Bearer eu-jev-test-key"
|
||||
assert json.loads(sent.content) == body
|
||||
|
||||
def test_rejects_custom_body_that_would_replace_the_authorized_request(self, client: TestClient) -> None:
|
||||
smuggled: Final = {"model": "eu-jeff-latest", "state": "refund", "questions": {"q": {"type": "noul"}}}
|
||||
with respx.mock(assert_all_called=False) as upstream:
|
||||
route: Final = upstream.post("https://eu-jev.example/base/v1/systemone").respond(200, json={"answers": {}})
|
||||
response: Final = client.post("/eu_jev/v1/systemone", json={"model": "gpt-4o", "custom_body": smuggled})
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "custom_body" in response.text
|
||||
assert not route.called
|
||||
|
||||
def test_rejects_streaming_that_would_skip_spend_tracking(self, client: TestClient) -> None:
|
||||
with respx.mock(assert_all_called=False) as upstream:
|
||||
route: Final = upstream.post("https://eu-jev.example/base/v1/systemone").respond(200, json={"answers": {}})
|
||||
response: Final = client.post(
|
||||
"/eu_jev/v1/systemone", json={"model": "eu-jeff-latest", "state": "x", "stream": True}
|
||||
)
|
||||
|
||||
assert response.status_code == 400
|
||||
assert "Streaming" in response.text
|
||||
assert not route.called
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_forwards_target_auth_headers_provider_and_query(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("EU_JEV_API_KEY", "eu-jev-test-key")
|
||||
monkeypatch.setenv("EU_JEV_API_BASE", "https://eu-jev.example/base")
|
||||
|
||||
async def fake_upstream(request, *_args):
|
||||
target: Final = create_route.call_args.kwargs["target"]
|
||||
upstream_url: Final = httpx.URL(target).copy_merge_params(request.query_params)
|
||||
return Response(content=json.dumps({"upstream_query": parse_qs(upstream_url.query.decode())}))
|
||||
|
||||
endpoint_func = AsyncMock(side_effect=fake_upstream)
|
||||
create_route = Mock(return_value=endpoint_func)
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.create_pass_through_route",
|
||||
create_route,
|
||||
)
|
||||
|
||||
result = await eu_jev_proxy_route(
|
||||
endpoint="v1/systemone",
|
||||
request=self._request({"state": "x"}, {"trace": "yes"}),
|
||||
fastapi_response=MagicMock(spec=Response),
|
||||
user_api_key_dict=UserAPIKeyAuth(api_key="virtual-key"),
|
||||
)
|
||||
|
||||
assert json.loads(result.body) == {"upstream_query": {"trace": ["yes"]}}
|
||||
endpoint_func.assert_awaited_once()
|
||||
create_route.assert_called_once_with(
|
||||
endpoint="v1/systemone",
|
||||
target="https://eu-jev.example/base/v1/systemone",
|
||||
custom_headers={
|
||||
"Authorization": "Bearer eu-jev-test-key",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
custom_llm_provider="eu_jev",
|
||||
is_streaming_request=False,
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_uses_the_hosted_api_when_base_is_unset(self, monkeypatch: pytest.MonkeyPatch) -> None:
|
||||
monkeypatch.setenv("EU_JEV_API_KEY", "eu-jev-test-key")
|
||||
monkeypatch.delenv("EU_JEV_API_BASE", raising=False)
|
||||
|
||||
endpoint_func = AsyncMock(return_value=Response())
|
||||
create_route = Mock(return_value=endpoint_func)
|
||||
monkeypatch.setattr(
|
||||
"litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints.create_pass_through_route",
|
||||
create_route,
|
||||
)
|
||||
|
||||
await eu_jev_proxy_route(
|
||||
endpoint="v1/systemone",
|
||||
request=self._request({"state": "x"}),
|
||||
fastapi_response=MagicMock(spec=Response),
|
||||
user_api_key_dict=UserAPIKeyAuth(api_key="virtual-key"),
|
||||
)
|
||||
|
||||
assert create_route.call_args.kwargs["target"] == "https://eu-jev.com/v1/systemone"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("provider", ["laya", "bespoke"])
|
||||
class TestOssDecisionPassthroughRoute:
|
||||
@pytest.fixture
|
||||
|
|
|
|||
855
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
855
ui/litellm-dashboard/src/lib/http/schema.d.ts
generated
vendored
|
|
@ -5333,6 +5333,72 @@ export interface paths {
|
|||
patch: operations["assemblyai_proxy_route_eu_assemblyai__endpoint__patch"];
|
||||
trace?: never;
|
||||
};
|
||||
"/eu_jev/{endpoint}": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path?: never;
|
||||
cookie?: never;
|
||||
};
|
||||
/**
|
||||
* Eu Jev Proxy Route
|
||||
* @description Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
*
|
||||
* `POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
* and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
* rejected with a 400.
|
||||
*
|
||||
* [Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
*/
|
||||
get: operations["eu_jev_proxy_route_eu_jev__endpoint__get"];
|
||||
/**
|
||||
* Eu Jev Proxy Route
|
||||
* @description Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
*
|
||||
* `POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
* and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
* rejected with a 400.
|
||||
*
|
||||
* [Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
*/
|
||||
put: operations["eu_jev_proxy_route_eu_jev__endpoint__put"];
|
||||
/**
|
||||
* Eu Jev Proxy Route
|
||||
* @description Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
*
|
||||
* `POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
* and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
* rejected with a 400.
|
||||
*
|
||||
* [Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
*/
|
||||
post: operations["eu_jev_proxy_route_eu_jev__endpoint__post"];
|
||||
/**
|
||||
* Eu Jev Proxy Route
|
||||
* @description Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
*
|
||||
* `POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
* and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
* rejected with a 400.
|
||||
*
|
||||
* [Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
*/
|
||||
delete: operations["eu_jev_proxy_route_eu_jev__endpoint__delete"];
|
||||
options?: never;
|
||||
head?: never;
|
||||
/**
|
||||
* Eu Jev Proxy Route
|
||||
* @description Forward a request to eu/jev, an EU-hosted decision API, with `EU_JEV_API_KEY`.
|
||||
*
|
||||
* `POST /eu_jev/v1/systemone` sends a `state` and one to eight named `questions` (`choice`, `noul` or `score`)
|
||||
* and returns one answer per question name, with spend booked from the reported `usage`. `custom_body` is
|
||||
* rejected with a 400.
|
||||
*
|
||||
* [Docs](https://docs.litellm.ai/docs/pass_through/eu_jev)
|
||||
*/
|
||||
patch: operations["eu_jev_proxy_route_eu_jev__endpoint__patch"];
|
||||
trace?: never;
|
||||
};
|
||||
"/extraction": {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
@ -32233,6 +32299,50 @@ export interface components {
|
|||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
/** EuJevDecisionResponse */
|
||||
EuJevDecisionResponse: {
|
||||
/**
|
||||
* Answers
|
||||
* @description One answer per question, under the same names
|
||||
*/
|
||||
answers: {
|
||||
[key: string]: components["schemas"]["ChoiceAnswer"] | components["schemas"]["NoulAnswer"] | components["schemas"]["ScoreAnswer"];
|
||||
};
|
||||
meta: components["schemas"]["EuJevMeta"];
|
||||
/**
|
||||
* Model
|
||||
* @description The release that answered, such as eu-jeff-1.0.0
|
||||
*/
|
||||
model: string;
|
||||
usage: components["schemas"]["EuJevUsage"];
|
||||
};
|
||||
/** EuJevMeta */
|
||||
EuJevMeta: {
|
||||
/**
|
||||
* Cost Eur
|
||||
* @description The exact charge in euros, on authenticated requests
|
||||
*/
|
||||
cost_eur?: string | null;
|
||||
/**
|
||||
* Latency Ms
|
||||
* @description Server-side time for token quoting, credit reservation and inference
|
||||
*/
|
||||
latency_ms: number;
|
||||
/**
|
||||
* Mode
|
||||
* @constant
|
||||
*/
|
||||
mode: "live";
|
||||
/** Request Id */
|
||||
request_id: string;
|
||||
};
|
||||
/** EuJevUsage */
|
||||
EuJevUsage: {
|
||||
/** Input Tokens */
|
||||
input_tokens: number;
|
||||
/** Output Tokens */
|
||||
output_tokens: number;
|
||||
};
|
||||
/**
|
||||
* Eval
|
||||
* @description Represents an evaluation from the OpenAI Evals API
|
||||
|
|
@ -59146,6 +59256,751 @@ export interface operations {
|
|||
};
|
||||
};
|
||||
};
|
||||
eu_jev_proxy_route_eu_jev__endpoint__get: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
endpoint: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
/**
|
||||
* @example {
|
||||
* "model": "eu-jeff-latest",
|
||||
* "questions": {
|
||||
* "frustration": {
|
||||
* "criteria": [
|
||||
* "calm",
|
||||
* "mildly annoyed",
|
||||
* "angry"
|
||||
* ],
|
||||
* "instructions": "How frustrated is the customer?",
|
||||
* "type": "score"
|
||||
* },
|
||||
* "is_refund_request": {
|
||||
* "instructions": "Is the customer asking for a refund?",
|
||||
* "type": "noul"
|
||||
* },
|
||||
* "team": {
|
||||
* "criteria": {
|
||||
* "billing": "Payments, invoices, and refunds",
|
||||
* "support": "Technical issues and bugs"
|
||||
* },
|
||||
* "instructions": "Which team should handle this?",
|
||||
* "type": "choice"
|
||||
* }
|
||||
* },
|
||||
* "state": "I was charged twice. Can I get a refund?"
|
||||
* }
|
||||
*/
|
||||
"application/json": {
|
||||
/**
|
||||
* Model
|
||||
* @description eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it
|
||||
* @default eu-jeff-latest
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* Questions
|
||||
* @description One to eight questions, keyed by names of up to 80 characters
|
||||
*/
|
||||
questions: {
|
||||
[key: string]: {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 64 options, option name to description. A null description uses the option name
|
||||
*/
|
||||
criteria: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
};
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "choice";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Optional descriptions of what true and false mean
|
||||
*/
|
||||
criteria?: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
} | null;
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "noul";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 10 level descriptions, ordered from low to high
|
||||
*/
|
||||
criteria: (string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null)[];
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "score";
|
||||
};
|
||||
};
|
||||
/**
|
||||
* State
|
||||
* @description The content to evaluate, a string of up to 100,000 characters or a JSON object or array
|
||||
*/
|
||||
state: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EuJevDecisionResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
eu_jev_proxy_route_eu_jev__endpoint__put: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
endpoint: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
/**
|
||||
* @example {
|
||||
* "model": "eu-jeff-latest",
|
||||
* "questions": {
|
||||
* "frustration": {
|
||||
* "criteria": [
|
||||
* "calm",
|
||||
* "mildly annoyed",
|
||||
* "angry"
|
||||
* ],
|
||||
* "instructions": "How frustrated is the customer?",
|
||||
* "type": "score"
|
||||
* },
|
||||
* "is_refund_request": {
|
||||
* "instructions": "Is the customer asking for a refund?",
|
||||
* "type": "noul"
|
||||
* },
|
||||
* "team": {
|
||||
* "criteria": {
|
||||
* "billing": "Payments, invoices, and refunds",
|
||||
* "support": "Technical issues and bugs"
|
||||
* },
|
||||
* "instructions": "Which team should handle this?",
|
||||
* "type": "choice"
|
||||
* }
|
||||
* },
|
||||
* "state": "I was charged twice. Can I get a refund?"
|
||||
* }
|
||||
*/
|
||||
"application/json": {
|
||||
/**
|
||||
* Model
|
||||
* @description eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it
|
||||
* @default eu-jeff-latest
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* Questions
|
||||
* @description One to eight questions, keyed by names of up to 80 characters
|
||||
*/
|
||||
questions: {
|
||||
[key: string]: {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 64 options, option name to description. A null description uses the option name
|
||||
*/
|
||||
criteria: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
};
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "choice";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Optional descriptions of what true and false mean
|
||||
*/
|
||||
criteria?: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
} | null;
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "noul";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 10 level descriptions, ordered from low to high
|
||||
*/
|
||||
criteria: (string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null)[];
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "score";
|
||||
};
|
||||
};
|
||||
/**
|
||||
* State
|
||||
* @description The content to evaluate, a string of up to 100,000 characters or a JSON object or array
|
||||
*/
|
||||
state: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EuJevDecisionResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
eu_jev_proxy_route_eu_jev__endpoint__post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
endpoint: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
/**
|
||||
* @example {
|
||||
* "model": "eu-jeff-latest",
|
||||
* "questions": {
|
||||
* "frustration": {
|
||||
* "criteria": [
|
||||
* "calm",
|
||||
* "mildly annoyed",
|
||||
* "angry"
|
||||
* ],
|
||||
* "instructions": "How frustrated is the customer?",
|
||||
* "type": "score"
|
||||
* },
|
||||
* "is_refund_request": {
|
||||
* "instructions": "Is the customer asking for a refund?",
|
||||
* "type": "noul"
|
||||
* },
|
||||
* "team": {
|
||||
* "criteria": {
|
||||
* "billing": "Payments, invoices, and refunds",
|
||||
* "support": "Technical issues and bugs"
|
||||
* },
|
||||
* "instructions": "Which team should handle this?",
|
||||
* "type": "choice"
|
||||
* }
|
||||
* },
|
||||
* "state": "I was charged twice. Can I get a refund?"
|
||||
* }
|
||||
*/
|
||||
"application/json": {
|
||||
/**
|
||||
* Model
|
||||
* @description eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it
|
||||
* @default eu-jeff-latest
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* Questions
|
||||
* @description One to eight questions, keyed by names of up to 80 characters
|
||||
*/
|
||||
questions: {
|
||||
[key: string]: {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 64 options, option name to description. A null description uses the option name
|
||||
*/
|
||||
criteria: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
};
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "choice";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Optional descriptions of what true and false mean
|
||||
*/
|
||||
criteria?: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
} | null;
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "noul";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 10 level descriptions, ordered from low to high
|
||||
*/
|
||||
criteria: (string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null)[];
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "score";
|
||||
};
|
||||
};
|
||||
/**
|
||||
* State
|
||||
* @description The content to evaluate, a string of up to 100,000 characters or a JSON object or array
|
||||
*/
|
||||
state: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EuJevDecisionResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
eu_jev_proxy_route_eu_jev__endpoint__delete: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
endpoint: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
/**
|
||||
* @example {
|
||||
* "model": "eu-jeff-latest",
|
||||
* "questions": {
|
||||
* "frustration": {
|
||||
* "criteria": [
|
||||
* "calm",
|
||||
* "mildly annoyed",
|
||||
* "angry"
|
||||
* ],
|
||||
* "instructions": "How frustrated is the customer?",
|
||||
* "type": "score"
|
||||
* },
|
||||
* "is_refund_request": {
|
||||
* "instructions": "Is the customer asking for a refund?",
|
||||
* "type": "noul"
|
||||
* },
|
||||
* "team": {
|
||||
* "criteria": {
|
||||
* "billing": "Payments, invoices, and refunds",
|
||||
* "support": "Technical issues and bugs"
|
||||
* },
|
||||
* "instructions": "Which team should handle this?",
|
||||
* "type": "choice"
|
||||
* }
|
||||
* },
|
||||
* "state": "I was charged twice. Can I get a refund?"
|
||||
* }
|
||||
*/
|
||||
"application/json": {
|
||||
/**
|
||||
* Model
|
||||
* @description eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it
|
||||
* @default eu-jeff-latest
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* Questions
|
||||
* @description One to eight questions, keyed by names of up to 80 characters
|
||||
*/
|
||||
questions: {
|
||||
[key: string]: {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 64 options, option name to description. A null description uses the option name
|
||||
*/
|
||||
criteria: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
};
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "choice";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Optional descriptions of what true and false mean
|
||||
*/
|
||||
criteria?: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
} | null;
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "noul";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 10 level descriptions, ordered from low to high
|
||||
*/
|
||||
criteria: (string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null)[];
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "score";
|
||||
};
|
||||
};
|
||||
/**
|
||||
* State
|
||||
* @description The content to evaluate, a string of up to 100,000 characters or a JSON object or array
|
||||
*/
|
||||
state: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EuJevDecisionResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
eu_jev_proxy_route_eu_jev__endpoint__patch: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
header?: never;
|
||||
path: {
|
||||
endpoint: string;
|
||||
};
|
||||
cookie?: never;
|
||||
};
|
||||
requestBody: {
|
||||
content: {
|
||||
/**
|
||||
* @example {
|
||||
* "model": "eu-jeff-latest",
|
||||
* "questions": {
|
||||
* "frustration": {
|
||||
* "criteria": [
|
||||
* "calm",
|
||||
* "mildly annoyed",
|
||||
* "angry"
|
||||
* ],
|
||||
* "instructions": "How frustrated is the customer?",
|
||||
* "type": "score"
|
||||
* },
|
||||
* "is_refund_request": {
|
||||
* "instructions": "Is the customer asking for a refund?",
|
||||
* "type": "noul"
|
||||
* },
|
||||
* "team": {
|
||||
* "criteria": {
|
||||
* "billing": "Payments, invoices, and refunds",
|
||||
* "support": "Technical issues and bugs"
|
||||
* },
|
||||
* "instructions": "Which team should handle this?",
|
||||
* "type": "choice"
|
||||
* }
|
||||
* },
|
||||
* "state": "I was charged twice. Can I get a refund?"
|
||||
* }
|
||||
*/
|
||||
"application/json": {
|
||||
/**
|
||||
* Model
|
||||
* @description eu-jeff-latest follows the current release, eu-jeff-1.0.0 pins it
|
||||
* @default eu-jeff-latest
|
||||
*/
|
||||
model?: string;
|
||||
/**
|
||||
* Questions
|
||||
* @description One to eight questions, keyed by names of up to 80 characters
|
||||
*/
|
||||
questions: {
|
||||
[key: string]: {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 64 options, option name to description. A null description uses the option name
|
||||
*/
|
||||
criteria: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
};
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "choice";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Optional descriptions of what true and false mean
|
||||
*/
|
||||
criteria?: {
|
||||
[key: string]: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
} | null;
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "noul";
|
||||
} | {
|
||||
/**
|
||||
* Criteria
|
||||
* @description Two to 10 level descriptions, ordered from low to high
|
||||
*/
|
||||
criteria: (string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null)[];
|
||||
/**
|
||||
* Instructions
|
||||
* @description Free text, or a JSON object, array or null that eu/jev serializes to text before inference
|
||||
*/
|
||||
instructions: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[] | null;
|
||||
/**
|
||||
* Type
|
||||
* @constant
|
||||
*/
|
||||
type: "score";
|
||||
};
|
||||
};
|
||||
/**
|
||||
* State
|
||||
* @description The content to evaluate, a string of up to 100,000 characters or a JSON object or array
|
||||
*/
|
||||
state: string | {
|
||||
[key: string]: unknown;
|
||||
} | unknown[];
|
||||
};
|
||||
};
|
||||
};
|
||||
responses: {
|
||||
/** @description Successful Response */
|
||||
200: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["EuJevDecisionResponse"];
|
||||
};
|
||||
};
|
||||
/** @description Validation Error */
|
||||
422: {
|
||||
headers: {
|
||||
[name: string]: unknown;
|
||||
};
|
||||
content: {
|
||||
"application/json": components["schemas"]["HTTPValidationError"];
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
extraction_extraction_post: {
|
||||
parameters: {
|
||||
query?: never;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue