Skip to content

fix: honor ModelConfig.spec.tls in the embedding path#1994

Open
davidkarlsen wants to merge 2 commits into
kagent-dev:mainfrom
davidkarlsen:fix/embedding-tls-config
Open

fix: honor ModelConfig.spec.tls in the embedding path#1994
davidkarlsen wants to merge 2 commits into
kagent-dev:mainfrom
davidkarlsen:fix/embedding-tls-config

Conversation

@davidkarlsen

Copy link
Copy Markdown

Problem

The chat/LLM path threads ModelConfig.spec.tls (disableVerify / caCertSecretRef / disableSystemCAs) into a custom httpx client, but the embedding path ignores TLS config entirely:

  • EmbeddingConfig (both Go and Python) carried no TLS fields.
  • _embed_openai constructed the OpenAI/AzureOpenAI client with no http_client override.

So embeddings (used for session-memory auto-save) fail behind a TLS-inspecting corporate proxy even when the embedding ModelConfig sets spec.tls.disableVerify: true — the setting has nowhere to go. Observed as:

kagent.adk.models._embedding - ERROR - Error generating embedding with provider=openai model=<embedding-model>: Connection error.

Fixes #1992.

Why a full-chain (Go + Python) fix

The TLS settings reach the Python agent only via the Go-serialized agent config. A Python-only change would be a no-op because the Go controller never populates the fields. Confirmed by tracing translateEmbeddingConfig -> ModelToEmbeddingConfig.

Changes

Go

  • Add TLSInsecureSkipVerify / TLSCACertPath / TLSDisableSystemCAs to EmbeddingConfig (+ UnmarshalJSON).
  • ModelToEmbeddingConfig copies the TLS pointers from each model variant's BaseModel. translateEmbeddingConfig already runs deriveTLSFields via translateModel, so the source model already carries them.

Python

  • Add tls_disable_verify / tls_ca_cert_path / tls_disable_system_cas to EmbeddingConfig, accepting the Go wire name tls_insecure_skip_verify via AliasChoices.
  • _embed_openai builds http_client=httpx.AsyncClient(verify=create_ssl_context(...)) for both AsyncOpenAI and AsyncAzureOpenAI — reusing the existing create_ssl_context helper. The custom client is built only when a TLS field is set, so the default path is unchanged.

Tests

  • Go: ModelToEmbeddingConfig propagates TLS across all model variants; UnmarshalJSON parses the TLS fields; no-TLS leaves them nil.
  • Python: _embed_openai wires create_ssl_context + http_client for disable-verify / custom-CA / Azure; no-TLS preserves the default client.
  • go test ./api/adk/... ./core/internal/controller/translator/agent/... -> ok. pytest .../test_embedding_tls.py -> 4 passed. (Pre-existing test_tls_e2e.py failures are unrelated — they need a cert fixture and fail identically on main.)

The chat/LLM path threads spec.tls (disableVerify / caCertSecretRef /
disableSystemCAs) into a custom httpx client, but the embedding path
ignored TLS config entirely: EmbeddingConfig carried no TLS fields and
_embed_openai built the OpenAI client with no http_client override. As a
result, embeddings (session-memory auto-save) fail behind a TLS-inspecting
proxy even when the embedding ModelConfig sets spec.tls.disableVerify: true.

This is a full-chain fix: the TLS settings only reach the Python agent via
the Go-serialized config, so a Python-only change would be a no-op.

Go:
- Add TLSInsecureSkipVerify / TLSCACertPath / TLSDisableSystemCAs to
  EmbeddingConfig (+ UnmarshalJSON parsing).
- ModelToEmbeddingConfig copies the TLS pointers from each model variant's
  BaseModel. (translateEmbeddingConfig already runs deriveTLSFields via
  translateModel, so the source model carries them.)

Python:
- Add tls_disable_verify / tls_ca_cert_path / tls_disable_system_cas to
  EmbeddingConfig (accepting the Go wire name tls_insecure_skip_verify via
  AliasChoices).
- _embed_openai builds http_client=httpx.AsyncClient(verify=create_ssl_context(...))
  for both AsyncOpenAI and AsyncAzureOpenAI, only when a TLS field is set so
  the default path is unchanged.

Adds Go and Python unit tests covering propagation and client wiring.

Fixes kagent-dev#1992

Signed-off-by: David J. M. Karlsen <david@davidkarlsen.com>
Copilot AI review requested due to automatic review settings June 10, 2026 15:31
@github-actions github-actions Bot added the bug Something isn't working label Jun 10, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds end-to-end TLS/SSL configuration support for embedding requests so the Python embedding client honors the same TLS settings as the chat/LLM path (incl. Go → Python config propagation).

Changes:

  • Add TLS fields to EmbeddingConfig in both Go and Python (with Python accepting tls_insecure_skip_verify via alias).
  • Thread a TLS-aware httpx.AsyncClient(verify=...) into OpenAI / Azure OpenAI embedding SDK clients.
  • Add Go and Python unit tests validating TLS field propagation and client construction behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
python/packages/kagent-adk/tests/unittests/models/test_embedding_tls.py Adds unit tests asserting TLS config results in the expected httpx/OpenAI client wiring.
python/packages/kagent-adk/src/kagent/adk/types.py Extends EmbeddingConfig with TLS fields and an alias for tls_insecure_skip_verify.
python/packages/kagent-adk/src/kagent/adk/models/_embedding.py Builds and injects a TLS-configured httpx.AsyncClient into OpenAI/Azure OpenAI embedding clients.
go/api/adk/types.go Extends Go EmbeddingConfig w/ TLS fields; propagates TLS from BaseModel in ModelToEmbeddingConfig.
go/api/adk/types_test.go Adds tests for TLS JSON unmarshalling + TLS propagation into EmbeddingConfig.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 170 to +192
@@ -153,11 +179,17 @@ async def _embed_openai(self, texts: List[str]) -> List[List[float]]:
api_base = self.config.base_url or os.environ.get("AZURE_OPENAI_ENDPOINT")
if not api_base:
raise ValueError("Azure OpenAI endpoint must be set via base_url or AZURE_OPENAI_ENDPOINT env var")
client = AsyncAzureOpenAI(api_version=api_version, azure_endpoint=api_base)
azure_kwargs: dict[str, Any] = {"api_version": api_version, "azure_endpoint": api_base}
if http_client is not None:
azure_kwargs["http_client"] = http_client
client = AsyncAzureOpenAI(**azure_kwargs)
else:
from openai import AsyncOpenAI

client = AsyncOpenAI(base_url=self.config.base_url or None)
openai_kwargs: dict[str, Any] = {"base_url": self.config.base_url or None}
if http_client is not None:
openai_kwargs["http_client"] = http_client
client = AsyncOpenAI(**openai_kwargs)
Comment on lines +125 to +143
with mock.patch("kagent.adk.models._embedding.create_ssl_context") as mock_create_ssl:
with mock.patch("kagent.adk.models._embedding.httpx.AsyncClient") as mock_httpx:
with mock.patch("openai.AsyncAzureOpenAI") as mock_azure:
mock_create_ssl.return_value = False
mock_client = mock.MagicMock()
mock_httpx.return_value = mock_client
mock_azure.return_value.embeddings.create = mock.AsyncMock(
return_value=mock.MagicMock(data=[])
)

await embedding._embed_openai(["hello"])

mock_create_ssl.assert_called_once_with(
disable_verify=True,
ca_cert_path=None,
disable_system_cas=False,
)
azure_kwargs = mock_azure.call_args[1]
assert azure_kwargs["http_client"] is mock_client
Comment thread go/api/adk/types.go
Comment on lines +422 to +426
copyTLS := func(b BaseModel) {
e.TLSInsecureSkipVerify = b.TLSInsecureSkipVerify
e.TLSCACertPath = b.TLSCACertPath
e.TLSDisableSystemCAs = b.TLSDisableSystemCAs
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants