-
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
Changes from 6 commits
d4a4d18
df306a2
1ecc37b
b99400b
d3d88b6
f0b627f
dc00eb7
686bdcb
5736c4b
b2c7152
280723e
9eb3feb
d834b4e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,6 +69,8 @@ class TextLLMParams(SQLModel): | |
|
|
||
|
|
||
| class STTLLMParams(SQLModel): | ||
| model_config = {"extra": "forbid"} | ||
|
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. what it is for?
Collaborator
Author
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. this is to prevent typos or random keys from silently passing to crud layer. Currently if the user adds
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. understood |
||
|
|
||
| model: str = DEFAULT_STT_MODEL | ||
| instructions: str | None = None | ||
| input_language: str | None = "auto" | ||
|
|
@@ -86,17 +88,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): | ||
| 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 | ||
|
coderabbitai[bot] marked this conversation as resolved.
Outdated
|
||
|
|
||
|
|
||
| KaapiLLMParams = Union[TextLLMParams, STTLLMParams, TTSLLMParams, ProxyLLMParams] | ||
|
|
||
|
|
||
| # Input type models for discriminated union | ||
|
|
@@ -232,14 +252,16 @@ class NativeCompletionConfig(SQLModel): | |
| Supports any LLM provider's native API format. | ||
| """ | ||
|
|
||
| provider: Literal[ | ||
| "openai-native", | ||
| "google-native", | ||
| "sarvamai-native", | ||
| "elevenlabs-native", | ||
| "anthropic-native", | ||
| "google-vertex-native", | ||
| ] = Field( | ||
| provider: ( | ||
| Literal[ | ||
|
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. I will ad proxy value here in my PR. since it need migration to be added, so I will do it. |
||
| "openai-native", | ||
| "google-native", | ||
| "sarvamai-native", | ||
| "elevenlabs-native", | ||
| "anthropic-native", | ||
| "google-vertex-native", | ||
| ] | ||
| ) = Field( | ||
| ..., | ||
| description="Native provider type (e.g., openai-native)", | ||
| ) | ||
|
|
@@ -306,9 +328,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): | ||
| 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"), | ||
| ] | ||
|
|
||
|
|
@@ -326,6 +378,21 @@ 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") == "proxy": | ||
| existing = completion.get("provider") | ||
| if existing in (None, "proxy"): | ||
| completion["provider"] = "proxy" | ||
|
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. Same here, |
||
| return data | ||
|
|
||
| # used for llm-chain to provide prompt interpolation | ||
| prompt_template: PromptTemplate | None = Field( | ||
| default=None, | ||
|
|
||
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.
can we use the constent here like: