feat: add Azure OpenAI apiFormat for Chat Completions and Responses - #2626
Open
jeremiedeveloper wants to merge 2 commits into
Open
feat: add Azure OpenAI apiFormat for Chat Completions and Responses#2626jeremiedeveloper wants to merge 2 commits into
jeremiedeveloper wants to merge 2 commits into
Conversation
Signed-off-by: Jeremie Rouelle <jeremie.rouelle@hotmail.fr>
Complete apiFormat wiring for Azure OpenAI Chat Completions vs Responses: Python ADK client, Helm values/docs, CRD docs, and an example ModelConfig. Unit tests capture the two HTTP shapes. Opt-in Foundry live tests run only when AZURE_LIVE=1 so CI never calls Azure. Signed-off-by: Jeremie Rouelle <jeremie.rouelle@hotmail.fr>
jeremiedeveloper
requested review from
a team,
Charlesthebird,
peterj and
supreme-gg-gg
as code owners
August 29, 2026 18:35
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2517
Summary
Adds an
apiFormatdiscriminator onModelConfigso Azure OpenAI (and OpenAI-compatible) models can use either Chat Completions or the Responses API.apiFormatchatCompletions(default, omitted = this)POST {endpoint}/openai/deployments/{deployment}/chat/completions?api-version=...responsesPOST {endpoint}/openai/v1/responses— deployment name is the JSONmodel; noapi-versionqueryNeeded because some Azure / Foundry deployments (newer GPT-5 class, etc.) reject Chat Completions. Existing configs stay valid: the field is optional and CEL/Helm default to Chat Completions.
User-facing config
Helm:
Example manifest:
examples/modelconfig-azure-openai-responses.yaml(placeholder secret, same style asexamples/modelconfig-with-tls.yaml).What changed, by file
API / CRD
go/api/v1alpha3/modelconfig_types.go—OpenAIAPIFormatenum (chatCompletions|responses) on bothopenAIandazureOpenAI. Kubebuilder defaultchatCompletions. Comments describe the two Azure URL shapes.go/api/v1alpha3/modelconfig_cel_test.go— CEL accepts both values; rejects unknownapiFormat.go/api/v1alpha3/zz_generated.deepcopy.go,go/api/config/crd/bases/kagent.dev_modelconfigs.yaml,helm/kagent-crds/templates/kagent.dev_modelconfigs.yaml— generated CRD so the field is served on v1alpha3.go/api/adk/types.go—APIFormaton the translated ADK Azure/OpenAI model so runtimes see it.ui/src/types/index.ts— TypeScript union for the UI.Go runtime
go/adk/pkg/internal/azureai/azureai.go— shared Azure OpenAI client.Responses: false(default) keeps{endpoint}/openai/deployments/{dep}/+api-version.Responses: trueuses{endpoint}/openai/v1/and does not sendapi-version. Auth is stillApi-Key(or Azure AD), withAuthorizationstripped so a leftoverOPENAI_API_KEYis not leaked to Azure.go/adk/pkg/models/openai.go—NewAzureOpenAIModel*setsClientConfig.Responsesfromconfig.APIFormat == responsesand logsapiFormat.go/adk/pkg/agent/agent.go— agent construction passesapiFormatthrough.Translators (declarative + v2)
go/core/internal/controller/translator/agent/adk_api_translator.go— copiesModelConfig.spec.azureOpenAI.apiFormat/openAI.apiFormatontoadk.AzureOpenAI/adk.OpenAI.go/core/v2/translator/model.go— same for Harness / AgentTemplate revisions (KAGENT_CONFIG_JSON).Python runtime
python/packages/kagent-adk/src/kagent/adk/types.py—api_formaton the Azure/OpenAI model config;to_agent()passes it intoAzureOpenAI.python/packages/kagent-adk/src/kagent/adk/models/_openai.py—api_format: chatCompletions | responses. On Azure +responses, buildsAsyncOpenAI(base_url="{endpoint}/openai/v1/", Api-Key header)instead ofAsyncAzureOpenAI.generate_content_asyncbranches to the Responses path.python/packages/kagent-adk/src/kagent/adk/models/_openai_responses.py— converts genaiContent↔ Responsesinputitems (text, function calls/outputs, images) and streamsresponses.create.Helm / docs
helm/kagent/values.yaml— commentedapiFormat: responsesunder Azure.helm/kagent/tests/modelconfig_test.yaml— helm-unittest: when set, the rendered ModelConfig hasspec.azureOpenAI.apiFormat: responses.helm/README.md,docs/architecture/crds-and-types.md— document the field..gitignore— comment that.local/is Kind/Azure smoke only (keys,values.local.yaml, reports). Does not ignore any feature source.Tests
Unit (CI, no Azure account)
Go — HTTP path capture with
httptestgo/adk/pkg/internal/azureai/azureai_test.gogo/adk/pkg/models/azure_openai_test.goAssert:
chatCompletions→/openai/deployments/{deployment}/chat/completions+api-version=2024-06-01responses→/openai/v1/responsesand emptyapi-versionGenerateContentstill returns model textGo — translator
go/core/internal/controller/translator/agent/azure_openai_translator_test.go—apiFormat: responseslands onadk.AzureOpenAI.APIFormat; omitted → empty (runtime default).Python — client + generate_content
python/packages/kagent-adk/tests/unittests/models/test_openai.pyAssert:
api_format=responsesconstructsAsyncOpenAIwithbase_url=.../openai/v1/andApi-Key; noapi_versionAsyncAzureOpenAI(azure_endpoint, api_version)generate_content_asyncwithresponsescallsclient.responses.create, notchat.completions.createapi_format=chatCompletionscallschat.completions.create, notresponses.createAgentConfig.to_agent()keepsapi_format, endpoint, deployment, api_versionHelm
helm/kagent/tests/modelconfig_test.yaml— rendered CR hasapiFormat: responseswhen values set it.Commands:
Live Azure AI Foundry (opt-in, skipped in CI)
Same skip style as existing kagent tests (
KAGENT_E2E_GRPC_TARGET,RUN_UPGRADE_TESTS): no env → skip, somake testdoes not call Azure and does not spend quota.Extra gate
AZURE_LIVE=1so a leftoverAZURE_OPENAI_API_KEYin the shell does not accidentally bill Foundry during normal unit runs.Recorded against Foundry GPT-4.1 (Go client + Python
AgentConfig.to_agent):/openai/deployments/gpt-4.1/chat/completions?api-version=2024-06-01pong/openai/v1/responses(noapi-version)pongpong/openai/v1/responsespongKind smoke (Go
golang-adkHarness + two AgentTemplates) also returnedpongfor both ModelConfigs. UI/atenet TLS to the worker is a local Substrate cert issue, not this API.Compatibility
apiFormat= Chat Completions (previous behavior)..env/values.local.yaml.