-
Notifications
You must be signed in to change notification settings - Fork 406
Feature: UI dynamic provider model discovery #1274
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
base: main
Are you sure you want to change the base?
Changes from all commits
cf5ca24
772d4a2
2833040
68df742
bb38ad2
1de291b
d870da4
1b302d7
3269e81
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 |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| /* | ||
| Copyright 2025. | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| */ | ||
|
|
||
| package v1alpha2 | ||
|
|
||
| import ( | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| ) | ||
|
|
||
| const ( | ||
| // ProviderConditionTypeReady indicates whether the provider is ready for use | ||
| ProviderConditionTypeReady = "Ready" | ||
|
|
||
| // ProviderConditionTypeSecretResolved indicates whether the provider's secret reference is valid | ||
| ProviderConditionTypeSecretResolved = "SecretResolved" | ||
|
|
||
| // ProviderConditionTypeModelsDiscovered indicates whether model discovery has succeeded | ||
| ProviderConditionTypeModelsDiscovered = "ModelsDiscovered" | ||
| ) | ||
|
|
||
| // DefaultProviderEndpoint returns the default API endpoint for a given provider type. | ||
| // Returns empty string if no default is defined. | ||
| func DefaultProviderEndpoint(providerType ModelProvider) string { | ||
| switch providerType { | ||
| case ModelProviderOpenAI: | ||
| return "https://api.openai.com/v1" | ||
| case ModelProviderAnthropic: | ||
| return "https://api.anthropic.com" | ||
| case ModelProviderGemini: | ||
| return "https://generativelanguage.googleapis.com" | ||
| case ModelProviderOllama: | ||
| return "http://localhost:11434" | ||
| default: | ||
| // Azure, Bedrock, Vertex AI require user-specific endpoints | ||
| return "" | ||
| } | ||
| } | ||
|
|
||
| // SecretReference contains information to locate a secret. | ||
| type SecretReference struct { | ||
| // Name is the name of the secret in the same namespace as the Provider | ||
| // +required | ||
| Name string `json:"name"` | ||
|
|
||
| // Key is the key within the secret that contains the API key or credential | ||
| // +required | ||
| Key string `json:"key"` | ||
| } | ||
|
|
||
| // ProviderSpec defines the desired state of Provider. | ||
| // | ||
| // +kubebuilder:validation:XValidation:message="endpoint must be a valid URL starting with http:// or https://",rule="!has(self.endpoint) || self.endpoint == '' || self.endpoint.startsWith('http://') || self.endpoint.startsWith('https://')" | ||
| // +kubebuilder:validation:XValidation:message="secretRef is required for providers that need authentication (not Ollama)",rule="self.type == 'Ollama' || (has(self.secretRef) && has(self.secretRef.name) && size(self.secretRef.name) > 0 && has(self.secretRef.key) && size(self.secretRef.key) > 0)" | ||
| type ProviderSpec struct { | ||
| // Type is the model provider type (OpenAI, Anthropic, etc.) | ||
| // +required | ||
| // +kubebuilder:validation:Required | ||
| Type ModelProvider `json:"type"` | ||
|
|
||
| // Endpoint is the API endpoint URL for the provider. | ||
| // If not specified, the default endpoint for the provider type will be used. | ||
| // +optional | ||
| // +kubebuilder:validation:Pattern=`^https?://.*` | ||
| Endpoint string `json:"endpoint,omitempty"` | ||
|
|
||
| // SecretRef references the Kubernetes Secret containing the API key. | ||
| // Optional for providers that don't require authentication (e.g., local Ollama). | ||
| // +optional | ||
| SecretRef *SecretReference `json:"secretRef,omitempty"` | ||
| } | ||
|
|
||
| // GetEndpoint returns the endpoint, or the default endpoint if not specified. | ||
| func (p *ProviderSpec) GetEndpoint() string { | ||
| if p.Endpoint != "" { | ||
| return p.Endpoint | ||
| } | ||
| return DefaultProviderEndpoint(p.Type) | ||
| } | ||
|
|
||
| // RequiresSecret returns true if this provider type requires a secret for authentication. | ||
| func (p *ProviderSpec) RequiresSecret() bool { | ||
| return p.Type != ModelProviderOllama | ||
| } | ||
|
|
||
| // ProviderStatus defines the observed state of Provider. | ||
| type ProviderStatus struct { | ||
| // ObservedGeneration reflects the generation of the most recently observed Provider spec | ||
| // +optional | ||
| ObservedGeneration int64 `json:"observedGeneration,omitempty"` | ||
|
|
||
| // Conditions represent the latest available observations of the Provider's state | ||
| // +optional | ||
| // +listType=map | ||
| // +listMapKey=type | ||
| Conditions []metav1.Condition `json:"conditions,omitempty"` | ||
|
|
||
| // DiscoveredModels is the cached list of model IDs available from this provider | ||
| // +optional | ||
| DiscoveredModels []string `json:"discoveredModels,omitempty"` | ||
|
|
||
| // ModelCount is the number of discovered models (for kubectl display) | ||
| // +optional | ||
| ModelCount int `json:"modelCount,omitempty"` | ||
|
|
||
| // LastDiscoveryTime is the timestamp of the last successful model discovery | ||
| // +optional | ||
| LastDiscoveryTime *metav1.Time `json:"lastDiscoveryTime,omitempty"` | ||
|
|
||
| // SecretHash is a hash of the referenced secret data, used to detect secret changes | ||
| // +optional | ||
| SecretHash string `json:"secretHash,omitempty"` | ||
| } | ||
|
|
||
| // +kubebuilder:object:root=true | ||
| // +kubebuilder:resource:categories=kagent,shortName=prov | ||
| // +kubebuilder:subresource:status | ||
| // +kubebuilder:printcolumn:name="Type",type="string",JSONPath=".spec.type" | ||
| // +kubebuilder:printcolumn:name="Endpoint",type="string",JSONPath=".spec.endpoint" | ||
| // +kubebuilder:printcolumn:name="Models",type="integer",JSONPath=".status.modelCount" | ||
| // +kubebuilder:printcolumn:name="Ready",type="string",JSONPath=".status.conditions[?(@.type=='Ready')].status" | ||
| // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" | ||
| // +kubebuilder:storageversion | ||
|
|
||
| // Provider is the Schema for the providers API. | ||
| // It represents a model provider configuration with automatic model discovery. | ||
| type Provider struct { | ||
|
Contributor
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 think we should rename this to model provider so it's more clear what the purpose is, what do youthink?
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. Agree, provider seems too vague, I will change this to modelprovider similar to modelconfig |
||
| metav1.TypeMeta `json:",inline"` | ||
| metav1.ObjectMeta `json:"metadata,omitempty"` | ||
|
|
||
| Spec ProviderSpec `json:"spec,omitempty"` | ||
| Status ProviderStatus `json:"status,omitempty"` | ||
| } | ||
|
|
||
| // +kubebuilder:object:root=true | ||
|
|
||
| // ProviderList contains a list of Provider. | ||
| type ProviderList struct { | ||
| metav1.TypeMeta `json:",inline"` | ||
| metav1.ListMeta `json:"metadata,omitempty"` | ||
| Items []Provider `json:"items"` | ||
| } | ||
|
|
||
| func init() { | ||
| SchemeBuilder.Register(&Provider{}, &ProviderList{}) | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
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.
Another API nit, why is this required? If there's only one key in the secret we can use that. Just small usability things.