Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
26c8c61
feat(dotAI): replace OpenAIClient with LangChain4J abstraction layer …
ihoffmann-dot Mar 24, 2026
48f268b
feat(dotAI): remove legacy config support, require providerConfig
ihoffmann-dot Mar 24, 2026
0e56d8c
test(dotAI): add unit and integration tests for LangChain4J client layer
ihoffmann-dot Mar 25, 2026
5179db3
fix(dotAI): change BOOL+hidden params to STRING in dotAI.yml
ihoffmann-dot Mar 25, 2026
86057b1
fix(dotAI): remove legacy hidden params from dotAI.yml
ihoffmann-dot Mar 25, 2026
3a5387c
fix(dotAI): update dotAI.yml description to reflect LangChain4J integ…
ihoffmann-dot Mar 26, 2026
ebbeaf1
fix(dotAI): remove legacy OpenAI model validation from AIAppValidator
ihoffmann-dot Mar 26, 2026
3de8a67
fix(dotAI): update /completions/config to reflect providerConfig-base…
ihoffmann-dot Mar 26, 2026
cfdd3cf
fix(dotAI): support maxCompletionTokens for o-series OpenAI models
ihoffmann-dot Mar 27, 2026
bfa54d1
fix(dotAI): replace legacy getApiKey guard with isEnabled in ImageRes…
ihoffmann-dot Mar 30, 2026
6a1213d
refactor(dotAI): remove dead OpenAI model-fetch flow from AIModels
ihoffmann-dot Mar 30, 2026
80820a6
fix(dotAI): handle base64 image responses for models that don't retur…
ihoffmann-dot Mar 30, 2026
07f7bc1
fix(dotAI): send text content (not token IDs) to LangChain4J embeddin…
ihoffmann-dot Mar 30, 2026
d79b37c
fix(dotAI): skip token encoding guard when model not in jtokkit registry
ihoffmann-dot Mar 30, 2026
46028c2
fix(dotAI): add missing IPUtils import in AIModelsTest
ihoffmann-dot Mar 31, 2026
abe115e
refactor(dotAI): PR review comments fixes
ihoffmann-dot Apr 1, 2026
e01cb46
refactor(dotAI): extract build helper in LangChain4jModelFactory to r…
ihoffmann-dot Apr 1, 2026
d9078de
refactor(dotAI): remove unused loadModels, activateModels and getAvai…
ihoffmann-dot Apr 1, 2026
ba7f173
refactor(dotAI): convert ProviderConfig to Immutables interface
ihoffmann-dot Apr 1, 2026
805fc7d
fix(dotAI): update unit tests for ProviderConfig Immutables migration
ihoffmann-dot Apr 2, 2026
14c417f
fix(dotAI): remove broken test methods for removed AIModels methods
ihoffmann-dot Apr 2, 2026
433c9c8
fix(dotAI): address Claude bot security and correctness review comments
ihoffmann-dot Apr 2, 2026
91ca878
fix(dotAI): remove maximumSize from model caches, keep TTL only
ihoffmann-dot Apr 2, 2026
92fae06
refactor(dotAI): remove dead AIModels and AIModelFallbackStrategy
ihoffmann-dot Apr 2, 2026
fe8cb0d
fix(dotAI): address remaining PR review comments
ihoffmann-dot Apr 6, 2026
52085fb
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 6, 2026
30b0a59
fix(dotAI): address remaining PR review comments
ihoffmann-dot Apr 6, 2026
598dac9
fix(dotAI): migrate integration tests to providerConfig flow
ihoffmann-dot Apr 6, 2026
4dd52e3
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 6, 2026
f754c93
feat(dotAI): add Azure OpenAI provider support
ihoffmann-dot Apr 6, 2026
48cf56c
test(dotAI): add Azure OpenAI factory tests, fix Netty/Reactor versio…
ihoffmann-dot Apr 6, 2026
025bb0c
style(dotAI): remove section comment from LangChain4jModelFactory
ihoffmann-dot Apr 6, 2026
111a0af
fix(dotAI): restore comment
ihoffmann-dot Apr 7, 2026
61a4c35
refactor(dotAI): address remaining PR review comments
ihoffmann-dot Apr 8, 2026
c5f873a
refactor(dotAI): address remaining PR review comments
ihoffmann-dot Apr 8, 2026
9c5509c
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 8, 2026
31cb86e
test(dotAI): fix WireMock stubs and CompletionsAPI for LangChain4J co…
ihoffmann-dot Apr 9, 2026
b44c35b
feat(dotAI): validate required ProviderConfig fields in LangChain4jMo…
ihoffmann-dot Apr 9, 2026
1d537af
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 9, 2026
039aae8
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 9, 2026
1dae27f
feat(dotAI): validate required Azure OpenAI fields in LangChain4jMode…
ihoffmann-dot Apr 9, 2026
17fd32a
test(dotAI): add missing validation tests to LangChain4jModelFactoryTest
ihoffmann-dot Apr 9, 2026
da008c0
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 9, 2026
18c5b44
fix(dotAI): remove legacy fields from config endpoint, fix providerCo…
ihoffmann-dot Apr 10, 2026
5fcd079
feat(dotAI): remove model/temperature params from workflow actionlets
ihoffmann-dot Apr 10, 2026
b1145dc
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 13, 2026
62d2e05
fix(dotAI): address PR review comments (dimensions, maxTokens, isEnab…
ihoffmann-dot Apr 13, 2026
111db46
feat(dotAI): implement streaming chat via LangChain4J StreamingChatModel
ihoffmann-dot Apr 13, 2026
ba763c6
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 13, 2026
d4b6855
feat(dotAI): add Azure OpenAI streaming chat support
ihoffmann-dot Apr 13, 2026
07252a4
fix(dotAI): use plain ObjectMapper for providerConfig redaction to av…
ihoffmann-dot Apr 14, 2026
924f6b2
fix(dotAI): use plain ObjectMapper in AppConfig, add isEnabled diagno…
ihoffmann-dot Apr 14, 2026
7fd1b4f
fix(dotAI): check providerConfig instead of apiKey for config warning…
ihoffmann-dot Apr 14, 2026
f3e1d0f
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 14, 2026
86e1776
fix(dotAI): allow unquoted control chars in providerConfig JSON parsing
ihoffmann-dot Apr 14, 2026
4fbb6a4
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 14, 2026
27cc6ee
fix(ai): strip control chars from providerConfig before JSON parse
ihoffmann-dot Apr 14, 2026
a39bf1c
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 14, 2026
b1dea4c
test(ai): add AppConfigTest for providerConfig JSON parsing with embe…
ihoffmann-dot Apr 14, 2026
4aaa0fd
fix(ai): sanitize providerConfig at construction time so all consumer…
ihoffmann-dot Apr 14, 2026
9e61911
debug(ai): log providerConfig snippet around parse error position
ihoffmann-dot Apr 14, 2026
1822dc8
fix(ai): restore DotObjectMapperProvider and remove diagnostic logging
ihoffmann-dot Apr 14, 2026
9e6a393
fix(ai): address PR review comments on LangChain4J integration
ihoffmann-dot Apr 15, 2026
c4421e5
fix(ai): replace new ObjectMapper() with DotObjectMapperProvider in C…
ihoffmann-dot Apr 15, 2026
febd3d7
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 15, 2026
187c493
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 15, 2026
92be76c
fix(ai): update Postman stubs and collection for LangChain4J migration
ihoffmann-dot Apr 15, 2026
fb72963
fix(ai): make imageSize optional in dotAI.yml
ihoffmann-dot Apr 15, 2026
df7d464
fix(ai): update WireMock body patterns for LangChain4J JSON spacing
ihoffmann-dot Apr 15, 2026
9acf22e
fix(ai): relax embedding count assertion to greaterThan(0)
ihoffmann-dot Apr 15, 2026
aefd7da
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 15, 2026
7587479
fix(ai): relax search result assertions to handle identical WireMock …
ihoffmann-dot Apr 15, 2026
2684167
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 15, 2026
0ca23c2
fix(ai): add missing openAiResponse fields and relax seo assertion
ihoffmann-dot Apr 16, 2026
ca551a5
fix(ai): update config endpoint and test to reflect new providerConfi…
ihoffmann-dot Apr 16, 2026
ff423a1
fix(ai-tests): convert SSE stubs to JSON, add stream-specific variant…
ihoffmann-dot Apr 16, 2026
6b094dd
fix(ai-tests): fix WireMock stub priority and pattern for AIViewToolT…
ihoffmann-dot Apr 16, 2026
d6b5788
fix(dotAI): apply PR review fixes (SSE double newline, null modelName…
ihoffmann-dot Apr 17, 2026
258dc17
Merge branch 'main' into dot-ai-langchain-integration
fabrizzio-dotCMS Apr 17, 2026
1632c7e
Merge branch 'main' into dot-ai-langchain-integration
fabrizzio-dotCMS Apr 17, 2026
af6109b
fix(dotAI): address PR review comments - stale logs, NPE, model overr…
ihoffmann-dot Apr 17, 2026
c79ac52
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 17, 2026
d426c74
fix(dotAI): address PR review comments - temperature guard, dead toke…
ihoffmann-dot Apr 17, 2026
2a3fa03
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 17, 2026
9525fc8
Merge branch 'main' into dot-ai-langchain-integration
fabrizzio-dotCMS Apr 17, 2026
4dbf79e
fix(dotAI): warn on temperature <= 0 in prompt()
ihoffmann-dot Apr 17, 2026
871cbda
fix(dotAI): add missing Logger import in CompletionsAPIImpl
ihoffmann-dot Apr 17, 2026
931000c
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 17, 2026
9e82c57
Merge branch 'main' into dot-ai-langchain-integration
ihoffmann-dot Apr 20, 2026
d17ac92
Merge branch 'dot-ai-langchain-integration' into dot-ai-langchain-azu…
ihoffmann-dot Apr 20, 2026
ea740e3
Merge branch 'main' into dot-ai-langchain-azure-openai
ihoffmann-dot Apr 21, 2026
7ac5733
Merge branch 'main' into dot-ai-langchain-azure-openai
ihoffmann-dot Apr 21, 2026
b716a43
fix(ai): remove duplicate BOM entry and allow deploymentName without …
ihoffmann-dot Apr 21, 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
44 changes: 39 additions & 5 deletions bom/application/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,46 @@
</dependency>


<!-- Asynchronous NIO client server framework for the jvm -->
<!-- <dependency>
<!-- reactor-core: pin to 3.4.41 to resolve conflict between existing deps (3.3.16)
and langchain4j-azure-open-ai (3.4+). Required for ContextView. -->
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.41</version>
</dependency>

<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
</dependency>-->
<!-- Netty: pin to 4.1.118.Final to resolve conflict between pgjdbc-ng (4.1.63)
and langchain4j-azure-open-ai (4.1.118). Required for DefaultHeaders$ValueValidator. -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>4.1.118.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>4.1.118.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>4.1.118.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-resolver</artifactId>
<version>4.1.118.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>4.1.118.Final</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>4.1.118.Final</version>
</dependency>


<!--
Expand Down
5 changes: 5 additions & 0 deletions dotCMS/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,11 @@
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<!-- LangChain4J Azure OpenAI provider: Chat, Embedding, Image models via Azure OpenAI Service -->
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-azure-open-ai</artifactId>
</dependency>
<dependency>
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package com.dotcms.ai.client.langchain4j;

import dev.langchain4j.model.azure.AzureOpenAiChatModel;
import dev.langchain4j.model.azure.AzureOpenAiEmbeddingModel;
import dev.langchain4j.model.azure.AzureOpenAiImageModel;
import dev.langchain4j.model.azure.AzureOpenAiStreamingChatModel;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.embedding.EmbeddingModel;
Expand All @@ -20,8 +24,8 @@
* To add support for a new provider, add a case to each switch block below.
* No other class needs to change.
*
* <p>Supported providers (Phase 1): {@code openai}
* <p>Planned (Phase 2): {@code azure_openai}, {@code bedrock}, {@code vertex_ai}
* <p>Supported providers: {@code openai}, {@code azure_openai}
* <p>Planned (Phase 2): {@code bedrock}, {@code vertex_ai}
*/
public class LangChain4jModelFactory {

Expand All @@ -35,7 +39,9 @@ private LangChain4jModelFactory() {}
* @throws IllegalArgumentException if config or provider is null, or the provider is unsupported
*/
public static ChatModel buildChatModel(final ProviderConfig config) {
return build(config, "chat", LangChain4jModelFactory::buildOpenAiChatModel);
return build(config, "chat",
LangChain4jModelFactory::buildOpenAiChatModel,
LangChain4jModelFactory::buildAzureOpenAiChatModel);
}

/**
Expand All @@ -46,7 +52,9 @@ public static ChatModel buildChatModel(final ProviderConfig config) {
* @throws IllegalArgumentException if config or provider is null, or the provider is unsupported
*/
public static StreamingChatModel buildStreamingChatModel(final ProviderConfig config) {
return build(config, "chat", LangChain4jModelFactory::buildOpenAiStreamingChatModel);
return build(config, "chat",
LangChain4jModelFactory::buildOpenAiStreamingChatModel,
LangChain4jModelFactory::buildAzureOpenAiStreamingChatModel);
}

/**
Expand All @@ -57,7 +65,9 @@ public static StreamingChatModel buildStreamingChatModel(final ProviderConfig co
* @throws IllegalArgumentException if config or provider is null, or the provider is unsupported
*/
public static EmbeddingModel buildEmbeddingModel(final ProviderConfig config) {
return build(config, "embeddings", LangChain4jModelFactory::buildOpenAiEmbeddingModel);
return build(config, "embeddings",
LangChain4jModelFactory::buildOpenAiEmbeddingModel,
LangChain4jModelFactory::buildAzureOpenAiEmbeddingModel);
}

/**
Expand All @@ -68,30 +78,46 @@ public static EmbeddingModel buildEmbeddingModel(final ProviderConfig config) {
* @throws IllegalArgumentException if config or provider is null, or the provider is unsupported
*/
public static ImageModel buildImageModel(final ProviderConfig config) {
return build(config, "image", LangChain4jModelFactory::buildOpenAiImageModel);
return build(config, "image",
LangChain4jModelFactory::buildOpenAiImageModel,
LangChain4jModelFactory::buildAzureOpenAiImageModel);
}

private static <T> T build(final ProviderConfig config,
final String modelType,
final Function<ProviderConfig, T> openAiFn) {
final Function<ProviderConfig, T> openAiFn,
final Function<ProviderConfig, T> azureOpenAiFn) {
if (config == null || config.provider() == null) {
throw new IllegalArgumentException("ProviderConfig or provider name is null for model type: " + modelType);
}
requireNonBlank(config.model(), "model", modelType);
switch (config.provider().toLowerCase()) {
case "openai":
requireNonBlank(config.model(), "model", modelType);
validateOpenAi(config, modelType);
return openAiFn.apply(config);
case "azure_openai":
validateAzureOpenAi(config, modelType);
return azureOpenAiFn.apply(config);
default:
throw new IllegalArgumentException("Unsupported " + modelType + " provider: "
+ config.provider() + ". Supported in Phase 1: openai");
+ config.provider() + ". Supported: openai, azure_openai");
}
}

private static void validateOpenAi(final ProviderConfig config, final String modelType) {
requireNonBlank(config.apiKey(), "apiKey", modelType);
}

private static void validateAzureOpenAi(final ProviderConfig config, final String modelType) {
requireNonBlank(config.apiKey(), "apiKey", modelType);
requireNonBlank(config.endpoint(), "endpoint", modelType);
if ((config.model() == null || config.model().isBlank())
&& (config.deploymentName() == null || config.deploymentName().isBlank())) {
throw new IllegalArgumentException(
"providerConfig." + modelType + ": either 'model' or 'deploymentName' is required for azure_openai");
}
}

private static void requireNonBlank(final String value, final String field, final String modelType) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(
Expand Down Expand Up @@ -162,4 +188,55 @@ private static ImageModel buildOpenAiImageModel(final ProviderConfig config) {
return builder.build();
}

// ── Azure OpenAI builders ─────────────────────────────────────────────────

private static StreamingChatModel buildAzureOpenAiStreamingChatModel(final ProviderConfig config) {
final AzureOpenAiStreamingChatModel.Builder builder = AzureOpenAiStreamingChatModel.builder()
.apiKey(config.apiKey())
.endpoint(config.endpoint())
.deploymentName(config.deploymentName() != null ? config.deploymentName() : config.model());
if (config.apiVersion() != null) builder.serviceVersion(config.apiVersion());
if (config.maxRetries() != null) builder.maxRetries(config.maxRetries());
if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout()));
if (config.temperature() != null) builder.temperature(config.temperature());
if (config.maxTokens() != null) builder.maxTokens(config.maxTokens());
return builder.build();
}

private static ChatModel buildAzureOpenAiChatModel(final ProviderConfig config) {
final AzureOpenAiChatModel.Builder builder = AzureOpenAiChatModel.builder()
.apiKey(config.apiKey())
.endpoint(config.endpoint())
.deploymentName(config.deploymentName() != null ? config.deploymentName() : config.model());
if (config.apiVersion() != null) builder.serviceVersion(config.apiVersion());
if (config.maxRetries() != null) builder.maxRetries(config.maxRetries());
if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout()));
if (config.temperature() != null) builder.temperature(config.temperature());
if (config.maxTokens() != null) builder.maxTokens(config.maxTokens());
return builder.build();
}

private static EmbeddingModel buildAzureOpenAiEmbeddingModel(final ProviderConfig config) {
final AzureOpenAiEmbeddingModel.Builder builder = AzureOpenAiEmbeddingModel.builder()
.apiKey(config.apiKey())
.endpoint(config.endpoint())
.deploymentName(config.deploymentName() != null ? config.deploymentName() : config.model());
if (config.apiVersion() != null) builder.serviceVersion(config.apiVersion());
if (config.maxRetries() != null) builder.maxRetries(config.maxRetries());
if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout()));
return builder.build();
}

private static ImageModel buildAzureOpenAiImageModel(final ProviderConfig config) {
final AzureOpenAiImageModel.Builder builder = AzureOpenAiImageModel.builder()
.apiKey(config.apiKey())
.endpoint(config.endpoint())
.deploymentName(config.deploymentName() != null ? config.deploymentName() : config.model());
if (config.apiVersion() != null) builder.serviceVersion(config.apiVersion());
if (config.maxRetries() != null) builder.maxRetries(config.maxRetries());
if (config.timeout() != null) builder.timeout(Duration.ofSeconds(config.timeout()));
if (config.size() != null) builder.size(config.size());
return builder.build();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,32 @@ public void test_buildChatModel_openai_missingApiKey_throws() {
assertThrows(IllegalArgumentException.class, () -> LangChain4jModelFactory.buildChatModel(config));
}

@Test
public void test_buildChatModel_azureOpenai_returnsModel() {
final ChatModel model = LangChain4jModelFactory.buildChatModel(azureOpenAiConfig("gpt-4o"));
assertNotNull(model);
}

@Test
public void test_buildChatModel_azureOpenai_missingApiKey_throws() {
final ProviderConfig config = ImmutableProviderConfig.builder()
.provider("azure_openai")
.model("gpt-4o")
.endpoint("https://my-company.openai.azure.com/")
.build();
assertThrows(IllegalArgumentException.class, () -> LangChain4jModelFactory.buildChatModel(config));
}

@Test
public void test_buildChatModel_azureOpenai_missingEndpoint_throws() {
final ProviderConfig config = ImmutableProviderConfig.builder()
.provider("azure_openai")
.model("gpt-4o")
.apiKey("test-key")
.build();
assertThrows(IllegalArgumentException.class, () -> LangChain4jModelFactory.buildChatModel(config));
}

@Test
public void test_buildChatModel_unknownProvider_throws() {
final ProviderConfig config = ImmutableProviderConfig.builder()
Expand All @@ -60,6 +86,12 @@ public void test_buildEmbeddingModel_openai_returnsModel() {
assertNotNull(model);
}

@Test
public void test_buildEmbeddingModel_azureOpenai_returnsModel() {
final EmbeddingModel model = LangChain4jModelFactory.buildEmbeddingModel(azureOpenAiConfig("text-embedding-ada-002"));
assertNotNull(model);
}

@Test
public void test_buildEmbeddingModel_unknownProvider_throws() {
final ProviderConfig config = ImmutableProviderConfig.builder()
Expand All @@ -81,6 +113,12 @@ public void test_buildImageModel_openai_returnsModel() {
assertNotNull(model);
}

@Test
public void test_buildImageModel_azureOpenai_returnsModel() {
final ImageModel model = LangChain4jModelFactory.buildImageModel(azureOpenAiConfig("dall-e-3"));
assertNotNull(model);
}

@Test
public void test_buildImageModel_unknownProvider_throws() {
final ProviderConfig config = ImmutableProviderConfig.builder()
Expand All @@ -99,4 +137,15 @@ private static ProviderConfig openAiConfig(final String model) {
.build();
}

private static ProviderConfig azureOpenAiConfig(final String model) {
return ImmutableProviderConfig.builder()
.provider("azure_openai")
.model(model)
.apiKey("test-key")
.endpoint("https://my-company.openai.azure.com/")
.deploymentName(model)
.apiVersion("2024-02-01")
.build();
}

}
Loading