Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 10
Unified API: Kaapi Backend as a Proxy#921
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
d4a4d18df306a21ecc37bb99400bd3d88b6f0b627fdc00eb7686bdcb5736c4bb2c7152280723e9eb3febd834b4eFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| from datetime import datetime | ||
| from enum import Enum | ||
| from typing import Annotated, Any, Literal, Union | ||
| from typing import Annotated, Any, Literal, Self, Union | ||
| from uuid import UUID, uuid4 | ||
| import sqlalchemy as sa | ||
| @@ -71,6 +71,8 @@ class TextLLMParams(SQLModel): | ||
| class STTLLMParams(SQLModel): | ||
| model_config = {"extra": "forbid"} | ||
| model: str = DEFAULT_STT_MODEL | ||
| instructions: str | None = None | ||
| input_language: str | None = "auto" | ||
| @@ -88,17 +90,35 @@ class STTLLMParams(SQLModel): | ||
| class TTSLLMParams(SQLModel): | ||
| model_config = {"extra": "forbid"} | ||
| model: str = DEFAULT_TTS_MODEL | ||
| voice: str = DEFAULT_TTS_VOICE | ||
| language: str | None = None | ||
| response_format: Literal["mp3", "wav", "ogg"] | None = "wav" | ||
| KaapiLLMParams = Union[ | ||
| TextLLMParams, | ||
| STTLLMParams, | ||
| TTSLLMParams, | ||
| ] | ||
| class ProxyLLMParams(SQLModel): | ||
| model_config = {"extra": "forbid"} | ||
| client_llm_url: HttpUrl = Field( | ||
| ..., | ||
| description=( | ||
| "HTTPS URL of the client's own LLM endpoint. Kaapi forwards the " | ||
| "(guardrail-sanitised) input here and applies output guardrails to the response." | ||
| ), | ||
| ) | ||
| @model_validator(mode="after") | ||
| def _require_https(self) -> Self: | ||
| if self.client_llm_url.scheme != "https": | ||
| raise ValueError( | ||
| f"client_llm_url must be HTTPS, got scheme: {self.client_llm_url.scheme}" | ||
| ) | ||
| return self | ||
| KaapiLLMParams = Union[TextLLMParams, STTLLMParams, TTSLLMParams, ProxyLLMParams] | ||
| # Input type models for discriminated union | ||
| @@ -313,9 +333,39 @@ def validate_params(self): | ||
| return self | ||
| class ProxyCompletionConfig(SQLModel): | ||
Collaborator There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we really need this ProxyCompletionConfig? can't we re-use class KaapiCompletionConfig(SQLModel) | ||
| """ | ||
| Proxy completion: Kaapi forwards the (guardrail-sanitised) input to the | ||
| client's own LLM endpoint and applies output guardrails to the response. | ||
| No upstream provider is dispatched — `provider` is fixed to "proxy" so | ||
| the discriminated union can route cleanly. | ||
| """ | ||
| provider: Literal["proxy"] = Field( | ||
| "proxy", | ||
| description=( | ||
| "Discriminator value for the proxy variant. Auto-injected when " | ||
| "type=proxy; clients may omit it." | ||
| ), | ||
| ) | ||
| type: Literal["proxy"] = Field(..., description="Must be 'proxy'.") | ||
| params: dict[str, Any] = Field( | ||
| ..., | ||
| description="Proxy params (client_llm_url, ...)", | ||
| ) | ||
| @model_validator(mode="after") | ||
| def validate_params(self) -> Self: | ||
| validated = ProxyLLMParams.model_validate(self.params) | ||
| # mode="json" coerces HttpUrl → plain str so downstream consumers | ||
| # (httpx.post, urlparse) get the type they expect from params dict. | ||
| self.params = validated.model_dump(mode="json", exclude_none=True) | ||
| return self | ||
| # Discriminated union for completion configs based on provider field | ||
| CompletionConfig = Annotated[ | ||
| Union[NativeCompletionConfig, KaapiCompletionConfig], | ||
| Union[NativeCompletionConfig, KaapiCompletionConfig, ProxyCompletionConfig], | ||
| Field(discriminator="provider"), | ||
| ] | ||
| @@ -333,6 +383,24 @@ class ConfigBlob(SQLModel): | ||
| completion: CompletionConfig = Field(..., description="Completion configuration") | ||
| @model_validator(mode="before") | ||
| @classmethod | ||
| def _default_proxy_provider(cls, data: Any) -> Any: | ||
| """For `type=proxy`, provider is meaningless to the caller. | ||
| Inject provider="proxy" so the CompletionConfig discriminator routes | ||
| to ProxyCompletionConfig without forcing the client to set it.""" | ||
| if not isinstance(data, dict): | ||
| return data | ||
| completion = data.get("completion") | ||
| if ( | ||
| isinstance(completion, dict) | ||
| and completion.get("type") == Provider.PROXY.value | ||
| ): | ||
| existing = completion.get("provider") | ||
| if existing in (None, Provider.PROXY.value): | ||
| completion["provider"] = Provider.PROXY.value | ||
| return data | ||
| # used for llm-chain to provide prompt interpolation | ||
| prompt_template: PromptTemplate | None = Field( | ||
| default=None, | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what it is for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is to prevent typos or random keys from silently passing to crud layer. Currently if the user adds
lorem:"ipsum"thats not a supported parameter, it silently strips that. Ideally it should throw an error at top level instead of at the provider layer. Did not restrict toTextLLMParamsas there are way too many params to take care of. But STT and TTS and Proxy has a small no. of params.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
understood