-
Notifications
You must be signed in to change notification settings - Fork 596
api: Add AgentgatewayBackend #12830
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?
api: Add AgentgatewayBackend #12830
Changes from all commits
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,355 @@ | ||
| package v1alpha1 | ||
|
|
||
| import ( | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| gwv1 "sigs.k8s.io/gateway-api/apis/v1" | ||
| ) | ||
|
|
||
| // +kubebuilder:rbac:groups=gateway.kgateway.dev,resources=agentgatewaybackends,verbs=get;list;watch | ||
| // +kubebuilder:rbac:groups=gateway.kgateway.dev,resources=agentgatewaybackends/status,verbs=get;update;patch | ||
|
|
||
| // +kubebuilder:printcolumn:name="Accepted",type=string,JSONPath=".status.conditions[?(@.type=='Accepted')].status",description="Backend configuration acceptance status" | ||
| // +kubebuilder:printcolumn:name="Age",type=date,JSONPath=".metadata.creationTimestamp",description="The age of the backend." | ||
|
|
||
| // +genclient | ||
| // +kubebuilder:object:root=true | ||
| // +kubebuilder:metadata:labels={app=kgateway,app.kubernetes.io/name=kgateway} | ||
| // +kubebuilder:resource:categories=kgateway,shortName=agbe | ||
| // +kubebuilder:subresource:status | ||
| type AgentgatewayBackend struct { | ||
| metav1.TypeMeta `json:",inline"` | ||
| // metadata for the object | ||
| // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata | ||
| metav1.ObjectMeta `json:"metadata,omitempty"` | ||
|
|
||
| // spec defines the desired state of AgentgatewayBackend. | ||
| Spec AgentgatewayBackendSpec `json:"spec"` | ||
|
|
||
| // status defines the current state of AgentgatewayBackend. | ||
| Status AgentgatewayBackendStatus `json:"status,omitempty"` | ||
| // TODO: embed this into a typed Status field when | ||
| // https://github.com/kubernetes/kubernetes/issues/131533 is resolved | ||
| } | ||
|
|
||
| // AgentgatewayBackend defines the observed state of AgentgatewayBackend. | ||
| type AgentgatewayBackendStatus struct { | ||
| // Conditions is the list of conditions for the backend. | ||
| // +listType=map | ||
| // +listMapKey=type | ||
| // +kubebuilder:validation:MaxItems=8 | ||
| Conditions []metav1.Condition `json:"conditions,omitempty"` | ||
| } | ||
|
|
||
| // +kubebuilder:object:root=true | ||
| type AgentgatewayBackendList struct { | ||
| metav1.TypeMeta `json:",inline"` | ||
| metav1.ListMeta `json:"metadata,omitempty"` | ||
| Items []AgentgatewayBackend `json:"items"` | ||
| } | ||
|
|
||
| // +kubebuilder:validation:ExactlyOneOf=ai;static;dynamicForwardProxy;mcp | ||
| type AgentgatewayBackendSpec struct { | ||
| // static represents a static hostname. | ||
| Static *AgentStaticBackend `json:"static,omitempty"` | ||
|
|
||
| // ai represents a LLM backend. | ||
| AI *AIBackend `json:"ai,omitempty"` | ||
|
|
||
| // mcp represents an MCP backend | ||
| NCO *MCPBackend `json:"mcp,omitempty"` | ||
|
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. NCO? 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. That is "MCP" when your fingers are 1 key shifted left 🙃 |
||
|
|
||
| // dynamicForwardProxy configures the proxy to dynamically send requests to the destination based on the incoming | ||
| // request HTTP host header, or TLS SNI for TLS traffic. | ||
| // | ||
| // Note: this Backend type enables users to send trigger the proxy to send requests to arbitrary destinations. Proper | ||
| // access controls must be put in place when using this backend type. | ||
| DynamicForwardProxy *AgentDynamicForwardProxyBackend `json:"dynamicForwardProxy,omitempty"` | ||
|
|
||
| // policies controls policies for communicating with this backend. Policies may also be set in AgentgatewayPolicy; | ||
| // policies are merged on a field-level basis, with policies on the Backend (this field) taking precedence. | ||
| Policies *AgentgatewayPolicyBackend `json:"policies,omitempty"` | ||
| } | ||
|
|
||
| type AgentDynamicForwardProxyBackend struct { | ||
| } | ||
|
|
||
| // AgentAppProtocol defines the application protocol to use when communicating with the backend. | ||
| // +kubebuilder:validation:Enum=kubernetes.io/h2c | ||
| type AgentAppProtocol string | ||
|
|
||
| const ( | ||
| // AppProtocolKubernetesH2C is the kubernetes.io/h2c app protocol. | ||
| AgentAppProtocolKubernetesH2C AgentAppProtocol = "kubernetes.io/h2c" | ||
| ) | ||
|
|
||
| type AgentStaticBackend struct { | ||
| // host to connect to. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| Host ShortString `json:"host"` | ||
| // port to connect to. | ||
| // +kubebuilder:validation:Minimum=1 | ||
| // +kubebuilder:validation:Maximum=65535 | ||
| Port int32 `json:"port"` | ||
|
|
||
| // appProtocol is the application protocol to use when communicating with the backend. | ||
| AppProtocol *AgentAppProtocol `json:"appProtocol,omitempty"` | ||
| } | ||
|
|
||
| // AIBackend specifies the AI backend configuration | ||
| // +kubebuilder:validation:ExactlyOneOf=provider;groups | ||
| type AIBackend struct { | ||
|
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. How do you configure |
||
| // provider specifies configuration for how to reach the configured LLM provider. | ||
| LLM *LLMProvider `json:"provider,omitempty"` | ||
|
|
||
| // groups specifies a list of groups in priority order where each group defines | ||
| // a set of LLM providers. The priority determines the priority of the backend endpoints chosen. | ||
| // Note: provider names must be unique across all providers in all priority groups. Backend policies | ||
| // may target a specific provider by name using targetRefs[].sectionName. | ||
| // | ||
| // Example configuration with two priority groups: | ||
| // ```yaml | ||
| // groups: | ||
| // - providers: | ||
| // - azureOpenai: | ||
| // deploymentName: gpt-4o-mini | ||
| // apiVersion: 2024-02-15-preview | ||
| // endpoint: ai-gateway.openai.azure.com | ||
| // authToken: | ||
| // secretRef: | ||
| // name: azure-secret | ||
| // namespace: kgateway-system | ||
| // - providers: | ||
| // - azureOpenai: | ||
| // deploymentName: gpt-4o-mini-2 | ||
| // apiVersion: 2024-02-15-preview | ||
| // endpoint: ai-gateway-2.openai.azure.com | ||
| // authToken: | ||
| // secretRef: | ||
| // name: azure-secret-2 | ||
| // namespace: kgateway-system | ||
| // ``` | ||
| // +kubebuilder:validation:MinItems=1 | ||
| // +kubebuilder:validation:MaxItems=32 | ||
| // TODO: enable this rule when we don't need to support older k8s versions where this rule breaks // +kubebuilder:validation:XValidation:message="provider names must be unique across groups",rule="self.map(pg, pg.providers.map(pp, pp.name)).map(p, self.map(pg, pg.providers.map(pp, pp.name)).filter(cp, cp != p).exists(cp, p.exists(pn, pn in cp))).exists(p, !p)" | ||
| PriorityGroups []PriorityGroup `json:"groups,omitempty"` | ||
| } | ||
|
|
||
| type PriorityGroup struct { | ||
| // providers specifies a list of LLM providers within this group. Each provider is treated equally in terms of priority, | ||
| // with automatic weighting based on health. | ||
| // | ||
| // +kubebuilder:validation:MinItems=1 | ||
| // +kubebuilder:validation:MaxItems=32 | ||
| // +kubebuilder:validation:XValidation:message="provider names must be unique within a group",rule="self.all(p1, self.exists_one(p2, p1.name == p2.name))" | ||
| Providers []NamedLLMProvider `json:"providers,omitempty"` | ||
| } | ||
|
|
||
| type NamedLLMProvider struct { | ||
| // Name of the provider. Policies can target this provider by name. | ||
| Name gwv1.SectionName `json:"name"` | ||
|
|
||
| // policies controls policies for communicating with this backend. Policies may also be set in AgentgatewayPolicy, or | ||
| // in the top level AgentgatewayBackend. policies are merged on a field-level basis, with order: AgentgatewayPolicy < | ||
| // AgentgatewayBackend < AgentgatewayBackend LLM provider (this field). | ||
| Policies *AgentgatewayPolicyBackend `json:"policies,omitempty"` | ||
|
|
||
| LLMProvider `json:",inline"` | ||
| } | ||
|
|
||
| // LLMProvider specifies the target large language model provider that the backend should route requests to. | ||
| // +kubebuilder:validation:ExactlyOneOf=openai;azureopenai;anthropic;gemini;vertexai;bedrock | ||
| // +kubebuilder:validation:XValidation:rule="has(self.host) || has(self.port) ? has(self.host) && has(self.port) : true",message="both host and port must be set together" | ||
| type LLMProvider struct { | ||
| // OpenAI provider | ||
| OpenAI *OpenAIConfig `json:"openai,omitempty"` | ||
|
|
||
| // Azure OpenAI provider | ||
| AzureOpenAI *AzureOpenAIConfig `json:"azureopenai,omitempty"` | ||
|
|
||
| // Anthropic provider | ||
| Anthropic *AnthropicConfig `json:"anthropic,omitempty"` | ||
|
|
||
| // Gemini provider | ||
| Gemini *GeminiConfig `json:"gemini,omitempty"` | ||
|
|
||
| // Vertex AI provider | ||
| VertexAI *VertexAIConfig `json:"vertexai,omitempty"` | ||
|
|
||
| // Bedrock provider | ||
| Bedrock *BedrockConfig `json:"bedrock,omitempty"` | ||
|
|
||
| // Host specifies the hostname to send the requests to. | ||
| // If not specified, the default hostname for the provider is used. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| Host ShortString `json:"host,omitempty"` | ||
|
|
||
| // Port specifies the port to send the requests to. | ||
| // +kubebuilder:validation:Minimum=1 | ||
| // +kubebuilder:validation:Maximum=65535 | ||
| Port int32 `json:"port,omitempty"` | ||
|
|
||
| // Path specifies the URL path to use for the LLM provider API requests. | ||
| // This is useful when you need to route requests to a different API endpoint while maintaining | ||
| // compatibility with the original provider's API structure. | ||
| // If not specified, the default path for the provider is used. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| // +kubebuilder:validation:MaxLength=1024 | ||
| Path string `json:"path,omitempty"` | ||
| } | ||
|
|
||
| // OpenAIConfig settings for the [OpenAI](https://platform.openai.com/docs/api-reference/streaming) LLM provider. | ||
| type OpenAIConfig struct{} | ||
|
|
||
| // AzureOpenAIConfig settings for the [Azure OpenAI](https://learn.microsoft.com/en-us/azure/ai-services/openai/) LLM provider. | ||
| type AzureOpenAIConfig struct { | ||
| // The endpoint for the Azure OpenAI API to use, such as `my-endpoint.openai.azure.com`. | ||
| // If the scheme is included, it is stripped. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| Endpoint ShortString `json:"endpoint"` | ||
|
|
||
| // The name of the Azure OpenAI model deployment to use. | ||
| // For more information, see the [Azure OpenAI model docs](https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/models). | ||
| // +kubebuilder:validation:MinLength=1 | ||
| DeploymentName ShortString `json:"deploymentName"` | ||
|
|
||
| // The version of the Azure OpenAI API to use. | ||
| // For more information, see the [Azure OpenAI API version reference](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#api-specs). | ||
| // +kubebuilder:validation:MinLength=1 | ||
| ApiVersion TinyString `json:"apiVersion"` | ||
| } | ||
|
|
||
| // GeminiConfig settings for the [Gemini](https://ai.google.dev/gemini-api/docs) LLM provider. | ||
| type GeminiConfig struct { | ||
| } | ||
|
|
||
| // Publisher configures the type of publisher model to use for VertexAI. Currently, only Google is supported. | ||
| type Publisher string | ||
|
|
||
| const ( | ||
| PublisherGoogle Publisher = "Google" | ||
| ) | ||
|
|
||
| // VertexAIConfig settings for the [Vertex AI](https://cloud.google.com/vertex-ai/docs) LLM provider. | ||
| type VertexAIConfig struct { | ||
| // The version of the Vertex AI API to use. | ||
| // For more information, see the [Vertex AI API reference](https://cloud.google.com/vertex-ai/docs/reference#versions). | ||
| // +kubebuilder:validation:MinLength=1 | ||
| ApiVersion TinyString `json:"apiVersion"` | ||
|
|
||
| // The ID of the Google Cloud Project that you use for the Vertex AI. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| ProjectId TinyString `json:"projectId"` | ||
|
|
||
| // The location of the Google Cloud Project that you use for the Vertex AI. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| Region TinyString `json:"region"` | ||
|
|
||
| // The type of publisher model to use. Currently, only Google is supported. | ||
| // +kubebuilder:validation:Enum=Google | ||
| Publisher Publisher `json:"publisher"` | ||
| } | ||
|
|
||
| // AnthropicConfig settings for the [Anthropic](https://docs.anthropic.com/en/release-notes/api) LLM provider. | ||
| type AnthropicConfig struct { | ||
| } | ||
|
|
||
| type BedrockConfig struct { | ||
| // Region is the AWS region to use for the backend. | ||
| // Defaults to us-east-1 if not specified. | ||
| // +optional | ||
| // +kubebuilder:default=us-east-1 | ||
| // +kubebuilder:validation:MinLength=1 | ||
| // +kubebuilder:validation:MaxLength=63 | ||
| // +kubebuilder:validation:Pattern="^[a-z0-9-]+$" | ||
| Region string `json:"region,omitempty"` | ||
|
|
||
| // Guardrail configures the Guardrail policy to use for the backend. See <https://docs.aws.amazon.com/bedrock/latest/userguide/guardrails.html> | ||
| // If not specified, the AWS Guardrail policy will not be used. | ||
| // +optional | ||
| Guardrail *AWSGuardrailConfig `json:"guardrail,omitempty"` | ||
| } | ||
|
|
||
| type AWSGuardrailConfig struct { | ||
| // GuardrailIdentifier is the identifier of the Guardrail policy to use for the backend. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| GuardrailIdentifier string `json:"identifier"` | ||
|
|
||
| // GuardrailVersion is the version of the Guardrail policy to use for the backend. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| GuardrailVersion string `json:"version"` | ||
| } | ||
|
|
||
| // MCPBackend configures mcp backends | ||
| type MCPBackend struct { | ||
| // Targets is a list of MCPBackend targets to use for this backend. | ||
| // Policies targeting MCPBackend targets must use targetRefs[].sectionName | ||
| // to select the target by name. | ||
| // +listType=map | ||
| // +listMapKey=name | ||
| // +kubebuilder:validation:MinItems=1 | ||
| // +kubebuilder:validation:MaxItems=32 | ||
| // +kubebuilder:validation:XValidation:message="target names must be unique",rule="self.all(t1, self.exists_one(t2, t1.name == t2.name))" | ||
| Targets []McpTargetSelector `json:"targets"` | ||
| } | ||
|
|
||
| // McpTargetSelector defines the MCPBackend target to use for this backend. | ||
| // +kubebuilder:validation:ExactlyOneOf=selector;static | ||
| type McpTargetSelector struct { | ||
| // Name of the MCPBackend target. | ||
| Name gwv1.SectionName `json:"name"` | ||
|
|
||
| // selector is a label selector is the selector to use to select Services. | ||
| // If policies are needed on a per-service basis, AgentgatewayPolicy can target the desired Service. | ||
| Selector *McpSelector `json:"selector,omitempty"` | ||
|
|
||
| // static configures a static MCP destination. When connecting to in-cluster Services, it is recommended to use | ||
| // 'selector' instead. | ||
| Static *McpTarget `json:"static,omitempty"` | ||
| } | ||
|
|
||
| // +kubebuilder:validation:AtLeastOneOf=namespaces;services | ||
| type McpSelector struct { | ||
| // namespace is the label selector in which namespaces Services should be selected from. | ||
| // If unset, only the namespace of the AgentgatewayBackend is searched. | ||
| Namespace *metav1.LabelSelector `json:"namespaces,omitempty"` | ||
|
|
||
| // services is the label selector for which Services should be selected. | ||
| Service *metav1.LabelSelector `json:"services,omitempty"` | ||
| } | ||
|
|
||
| // McpTarget defines a single MCPBackend target configuration. | ||
| type McpTarget struct { | ||
| // Host is the hostname or IP address of the MCPBackend target. | ||
| // +kubebuilder:validation:MinLength=1 | ||
| Host ShortString `json:"host"` | ||
|
|
||
| // Port is the port number of the MCPBackend target. | ||
| // +kubebuilder:validation:Minimum=1 | ||
| // +kubebuilder:validation:Maximum=65535 | ||
| Port int32 `json:"port"` | ||
|
|
||
| // Path is the URL path of the MCPBackend target endpoint. | ||
| // Defaults to "/sse" for SSE protocol or "/mcp" for StreamableHTTP protocol if not specified. | ||
| Path *string `json:"path,omitempty"` | ||
|
|
||
| // Protocol is the protocol to use for the connection to the MCPBackend target. | ||
| Protocol *MCPProtocol `json:"protocol,omitempty"` | ||
|
|
||
| // policies controls policies for communicating with this backend. Policies may also be set in AgentgatewayPolicy, or | ||
| // in the top level AgentgatewayBackend. Policies are merged on a field-level basis, with order: AgentgatewayPolicy < | ||
| // AgentgatewayBackend < AgentgatewayBackend MCP (this field). | ||
| Policies *AgentgatewayPolicyBackend `json:"policies,omitempty"` | ||
| } | ||
|
|
||
| // MCPProtocol defines the protocol to use for the MCPBackend target | ||
| // +kubebuilder:validation:Enum=StreamableHTTP;SSE | ||
| type MCPProtocol string | ||
|
|
||
| const ( | ||
|
|
||
| // MCPProtocolStreamableHTTP specifies Streamable HTTP must be used as the protocol | ||
| MCPProtocolStreamableHTTP MCPProtocol = "StreamableHTTP" | ||
|
|
||
| // MCPProtocolSSE specifies Server-Sent Events (SSE) must be used as the protocol | ||
| MCPProtocolSSE MCPProtocol = "SSE" | ||
| ) | ||
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.
How do host override and the other override options get configured now?
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.
Its still on AIBackend