Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4a2fc83
fix(translator): honor APIKeyPassthrough for Gemini provider
mesutoezdil Jun 18, 2026
2c5f4a9
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 18, 2026
adba18b
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 23, 2026
c587c00
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 24, 2026
6c21e96
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 24, 2026
a7644bd
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 25, 2026
3ca9822
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 25, 2026
5961abc
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 25, 2026
a3ab3d1
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 26, 2026
6992312
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 26, 2026
1ea9f5d
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 26, 2026
c5a670d
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 29, 2026
d88c382
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 29, 2026
e844032
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 30, 2026
843b4b2
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jun 30, 2026
4431ba5
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jul 1, 2026
4397763
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jul 2, 2026
ad46eef
Merge branch 'main' into fix/gemini-api-key-passthrough
mesutoezdil Jul 3, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -708,17 +708,19 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC

return ollama, modelDeploymentData, secretHashBytes, nil
case v1alpha2.ModelProviderGemini:
modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{
Name: env.GoogleAPIKey.Name(),
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: model.Spec.APIKeySecret,
if !model.Spec.APIKeyPassthrough && model.Spec.APIKeySecret != "" {
modelDeploymentData.EnvVars = append(modelDeploymentData.EnvVars, corev1.EnvVar{
Name: env.GoogleAPIKey.Name(),
ValueFrom: &corev1.EnvVarSource{
SecretKeyRef: &corev1.SecretKeySelector{
LocalObjectReference: corev1.LocalObjectReference{
Name: model.Spec.APIKeySecret,
},
Key: model.Spec.APIKeySecretKey,
},
Key: model.Spec.APIKeySecretKey,
},
},
})
})
}
gemini := &adk.Gemini{
BaseModel: adk.BaseModel{
Model: model.Spec.Model,
Expand All @@ -727,6 +729,7 @@ func (a *adkApiTranslator) translateModel(ctx context.Context, namespace, modelC
}
// Populate TLS fields in BaseModel
populateTLSFields(&gemini.BaseModel, model.Spec.TLS)
gemini.APIKeyPassthrough = model.Spec.APIKeyPassthrough
return gemini, modelDeploymentData, secretHashBytes, nil
Comment thread
mesutoezdil marked this conversation as resolved.
case v1alpha2.ModelProviderBedrock:
if model.Spec.Bedrock == nil {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
operation: translateAgent
targetObject: gemini-passthrough-agent
namespace: test
objects:
- apiVersion: kagent.dev/v1alpha2
kind: ModelConfig
metadata:
name: gemini-passthrough-model
namespace: test
spec:
provider: Gemini
model: gemini-2.0-flash
apiKeyPassthrough: true
- apiVersion: kagent.dev/v1alpha2
kind: Agent
metadata:
name: gemini-passthrough-agent
namespace: test
spec:
type: Declarative
declarative:
description: A Gemini agent using API key passthrough
systemMessage: You are a helpful assistant.
modelConfig: gemini-passthrough-model
tools: []
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
{
"agentCard": {
"capabilities": {
"streaming": true
},
"defaultInputModes": [
"text"
],
"defaultOutputModes": [
"text"
],
"description": "",
"name": "gemini_passthrough_agent",
"skills": null,
"supportedInterfaces": [
{
"protocolBinding": "JSONRPC",
"protocolVersion": "0.3",
"url": "http://gemini-passthrough-agent.test:8080"
},
{
"protocolBinding": "JSONRPC",
"protocolVersion": "1.0",
"url": "http://gemini-passthrough-agent.test:8080"
}
],
"version": ""
},
"config": {
"description": "",
"instruction": "You are a helpful assistant.",
"model": {
"api_key_passthrough": true,
"model": "gemini-2.0-flash",
"type": "gemini"
},
"stream": false
},
"manifest": [
{
"apiVersion": "v1",
"kind": "Secret",
"metadata": {
"labels": {
"app": "kagent",
"app.kubernetes.io/managed-by": "kagent",
"app.kubernetes.io/name": "gemini-passthrough-agent",
"app.kubernetes.io/part-of": "kagent",
"kagent": "gemini-passthrough-agent"
},
"name": "gemini-passthrough-agent",
"namespace": "test",
"ownerReferences": [
{
"apiVersion": "kagent.dev/v1alpha2",
"blockOwnerDeletion": true,
"controller": true,
"kind": "Agent",
"name": "gemini-passthrough-agent",
"uid": ""
}
]
},
"stringData": {
"agent-card.json": "{\n \"defaultInputModes\": [\n \"text\"\n ],\n \"defaultOutputModes\": [\n \"text\"\n ],\n \"description\": \"\",\n \"name\": \"gemini_passthrough_agent\",\n \"version\": \"\",\n \"skills\": [],\n \"capabilities\": {\n \"streaming\": true\n },\n \"supportedInterfaces\": [\n {\n \"url\": \"http://gemini-passthrough-agent.test:8080\",\n \"protocolBinding\": \"JSONRPC\",\n \"protocolVersion\": \"0.3\"\n },\n {\n \"url\": \"http://gemini-passthrough-agent.test:8080\",\n \"protocolBinding\": \"JSONRPC\",\n \"protocolVersion\": \"1.0\"\n }\n ],\n \"url\": \"http://gemini-passthrough-agent.test:8080\",\n \"protocolVersion\": \"0.3\",\n \"preferredTransport\": \"JSONRPC\"\n}",
"config.json": "{\"model\":{\"type\":\"gemini\",\"model\":\"gemini-2.0-flash\",\"api_key_passthrough\":true},\"description\":\"\",\"instruction\":\"You are a helpful assistant.\",\"stream\":false}"
}
},
{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": {
"labels": {
"app": "kagent",
"app.kubernetes.io/managed-by": "kagent",
"app.kubernetes.io/name": "gemini-passthrough-agent",
"app.kubernetes.io/part-of": "kagent",
"kagent": "gemini-passthrough-agent"
},
"name": "gemini-passthrough-agent",
"namespace": "test",
"ownerReferences": [
{
"apiVersion": "kagent.dev/v1alpha2",
"blockOwnerDeletion": true,
"controller": true,
"kind": "Agent",
"name": "gemini-passthrough-agent",
"uid": ""
}
]
}
},
{
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"labels": {
"app": "kagent",
"app.kubernetes.io/managed-by": "kagent",
"app.kubernetes.io/name": "gemini-passthrough-agent",
"app.kubernetes.io/part-of": "kagent",
"kagent": "gemini-passthrough-agent"
},
"name": "gemini-passthrough-agent",
"namespace": "test",
"ownerReferences": [
{
"apiVersion": "kagent.dev/v1alpha2",
"blockOwnerDeletion": true,
"controller": true,
"kind": "Agent",
"name": "gemini-passthrough-agent",
"uid": ""
}
]
},
"spec": {
"selector": {
"matchLabels": {
"app": "kagent",
"kagent": "gemini-passthrough-agent"
}
},
"strategy": {
"rollingUpdate": {
"maxSurge": 1,
"maxUnavailable": 0
},
"type": "RollingUpdate"
},
"template": {
"metadata": {
"annotations": {
"kagent.dev/config-hash": "4255145495309256999"
},
"labels": {
"app": "kagent",
"app.kubernetes.io/managed-by": "kagent",
"app.kubernetes.io/name": "gemini-passthrough-agent",
"app.kubernetes.io/part-of": "kagent",
"kagent": "gemini-passthrough-agent"
}
},
"spec": {
"containers": [
{
"args": [
"--host",
"0.0.0.0",
"--port",
"8080",
"--filepath",
"/config"
],
"env": [
{
"name": "KAGENT_NAMESPACE",
"valueFrom": {
"fieldRef": {
"fieldPath": "metadata.namespace"
}
}
},
{
"name": "KAGENT_NAME",
"value": "gemini-passthrough-agent"
},
{
"name": "KAGENT_URL",
"value": "http://kagent-controller.kagent:8083"
}
],
"image": "cr.kagent.dev/kagent-dev/kagent/app@sha256:test-app",
"imagePullPolicy": "IfNotPresent",
"name": "kagent",
"ports": [
{
"containerPort": 8080,
"name": "http"
}
],
"readinessProbe": {
"httpGet": {
"path": "/.well-known/agent-card.json",
"port": "http"
},
"initialDelaySeconds": 15,
"periodSeconds": 15,
"timeoutSeconds": 15
},
"resources": {
"limits": {
"cpu": "2",
"memory": "1Gi"
},
"requests": {
"cpu": "100m",
"memory": "384Mi"
}
},
"volumeMounts": [
{
"mountPath": "/config",
"name": "config"
},
{
"mountPath": "/var/run/secrets/tokens",
"name": "kagent-token"
}
]
}
],
"serviceAccountName": "gemini-passthrough-agent",
"volumes": [
{
"name": "config",
"secret": {
"secretName": "gemini-passthrough-agent"
}
},
{
"name": "kagent-token",
"projected": {
"sources": [
{
"serviceAccountToken": {
"audience": "kagent",
"expirationSeconds": 3600,
"path": "kagent-token"
}
}
]
}
}
]
}
}
},
"status": {}
},
{
"apiVersion": "v1",
"kind": "Service",
"metadata": {
"labels": {
"app": "kagent",
"app.kubernetes.io/managed-by": "kagent",
"app.kubernetes.io/name": "gemini-passthrough-agent",
"app.kubernetes.io/part-of": "kagent",
"kagent": "gemini-passthrough-agent"
},
"name": "gemini-passthrough-agent",
"namespace": "test",
"ownerReferences": [
{
"apiVersion": "kagent.dev/v1alpha2",
"blockOwnerDeletion": true,
"controller": true,
"kind": "Agent",
"name": "gemini-passthrough-agent",
"uid": ""
}
]
},
"spec": {
"ports": [
{
"name": "http",
"port": 8080,
"targetPort": 8080
}
],
"selector": {
"app": "kagent",
"kagent": "gemini-passthrough-agent"
},
"type": "ClusterIP"
},
"status": {
"loadBalancer": {}
}
}
]
}
15 changes: 13 additions & 2 deletions python/packages/kagent-adk/src/kagent/adk/models/_gemini.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ class KAgentGeminiLlm(KAgentTLSMixin, GeminiLLM):
extra_headers: Optional[dict[str, str]] = None
api_key_passthrough: Optional[bool] = None

_api_key: Optional[str] = None

model_config = {"arbitrary_types_allowed": True}

def set_passthrough_key(self, token: str) -> None:
"""Forward the Bearer token from the incoming request as the Gemini API key."""
self._api_key = token
self.__dict__.pop("api_client", None)
self.__dict__.pop("_live_api_client", None)

def _http_options(self, *, api_version: str | None = None) -> types.HttpOptions:
verify = self._tls_verify()
kwargs = {}
Expand All @@ -44,16 +52,19 @@ def _http_options(self, *, api_version: str | None = None) -> types.HttpOptions:
**kwargs,
)

def _resolve_api_key(self) -> Optional[str]:
return self._api_key or os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")

@cached_property
def api_client(self) -> Client:
return Client(
api_key=os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY"),
api_key=self._resolve_api_key(),
http_options=self._http_options(),
)

@cached_property
def _live_api_client(self) -> Client:
return Client(
api_key=os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY"),
api_key=self._resolve_api_key(),
http_options=self._http_options(api_version=self._live_api_version),
)
Loading
Loading