diff --git a/bom/pom.xml b/bom/pom.xml
index 149886f4d34..0f140eeba5a 100644
--- a/bom/pom.xml
+++ b/bom/pom.xml
@@ -350,6 +350,16 @@
helidon-microprofile-health
${helidon.version}
+
+ io.helidon.ia
+ helidon-ia-api
+ ${helidon.version}
+
+
+ io.helidon.ia
+ helidon-ia-openid
+ ${helidon.version}
+
io.helidon.microprofile.server
helidon-microprofile-server
diff --git a/ia/api/pom.xml b/ia/api/pom.xml
new file mode 100644
index 00000000000..96378bb67cb
--- /dev/null
+++ b/ia/api/pom.xml
@@ -0,0 +1,42 @@
+
+
+
+
+ 4.0.0
+
+ io.helidon.ia
+ helidon-ia-project
+ 4.1.0-SNAPSHOT
+
+
+ helidon-ia-api
+ Helidon IA API
+
+
+ Integration with IA API
+
+
+
+
+ io.helidon.common
+ helidon-common
+
+
+
+
diff --git a/ia/api/src/main/java/io/helidon/ia/api/ChatModel.java b/ia/api/src/main/java/io/helidon/ia/api/ChatModel.java
new file mode 100644
index 00000000000..acac403e36a
--- /dev/null
+++ b/ia/api/src/main/java/io/helidon/ia/api/ChatModel.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.api;
+
+/**
+ * Class to be extended by different LLM implementations that provides
+ * the methods to operate with it.
+ *
+ * @param the input of the LLM
+ * @param the output of LLM
+ */
+public interface ChatModel {
+
+ /**
+ * Invokes the LLM.
+ * Throws a runtime exception if errors.
+ *
+ * @param in the input of the LLM
+ * @return the output of LLM
+ */
+ OUT call(IN in);
+}
diff --git a/ia/api/src/main/java/module-info.java b/ia/api/src/main/java/module-info.java
new file mode 100644
index 00000000000..5a6ebca0fbc
--- /dev/null
+++ b/ia/api/src/main/java/module-info.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * IA API module.
+ *
+ */
+module io.helidon.ia.api {
+
+ requires io.helidon.common;
+
+ exports io.helidon.ia.api;
+}
\ No newline at end of file
diff --git a/ia/openai/pom.xml b/ia/openai/pom.xml
new file mode 100644
index 00000000000..c35723dfefe
--- /dev/null
+++ b/ia/openai/pom.xml
@@ -0,0 +1,62 @@
+
+
+
+
+ 4.0.0
+
+ io.helidon.ia
+ helidon-ia-project
+ 4.1.0-SNAPSHOT
+
+
+ helidon-ia-openai
+ Helidon IA OpenId
+
+
+ Integration with IA OpenId
+
+
+
+
+ io.helidon.ia
+ helidon-ia-api
+
+
+ io.helidon.webclient
+ helidon-webclient
+
+
+ io.helidon.http.media
+ helidon-http-media-jackson
+
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.mockito
+ mockito-core
+ test
+
+
+
+
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChatModel.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChatModel.java
new file mode 100644
index 00000000000..a9c7adc1972
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChatModel.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.net.URI;
+import java.util.Objects;
+
+import io.helidon.http.HeaderNames;
+import io.helidon.http.Status;
+import io.helidon.ia.api.ChatModel;
+import io.helidon.webclient.api.HttpClient;
+import io.helidon.webclient.api.HttpClientResponse;
+
+/**
+ * Class that handles OpenAI communications specified in
+ * Chat .
+ */
+public class OpenAIChatModel implements ChatModel {
+
+ private final HttpClient> httpClient;
+ private final URI uri;
+ private final String apiKey;
+
+ private OpenAIChatModel(HttpClient> httpClient, URI uri, String apiKey) {
+ this.httpClient = httpClient;
+ this.uri = uri;
+ this.apiKey = apiKey;
+ }
+
+ @Override
+ public OpenAIResponse call(OpenAIRequest in) {
+ HttpClientResponse response = httpClient.post(uri.toString())
+ .header(HeaderNames.CONTENT_TYPE, "application/json")
+ .header(HeaderNames.AUTHORIZATION, "Bearer " + apiKey)
+ .submit(in);
+ if (response.status() != Status.OK_200) {
+ throw new IllegalStateException("Invalid response " + response.status()
+ + ": " + response.as(String.class));
+ } else {
+ return response.as(OpenAIResponse.class);
+ }
+ }
+
+ /**
+ * Create a builder.
+ *
+ * @return a new fluent API builder
+ */
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ /**
+ * Create a OpenAIChatModel for the given API key and client.
+ *
+ * @param apiKey the OpenAI API key
+ * @param httpClient the HTTP Client
+ * @return a OpenAIChatModel default instance
+ */
+ public static OpenAIChatModel create(String apiKey, HttpClient> httpClient) {
+ return builder().apiKey(apiKey).client(httpClient).build();
+ }
+
+ /**
+ * Fluent API builder for {@link io.helidon.ia.openid.OpenAIChatModel}.
+ */
+ public static final class Builder implements io.helidon.common.Builder {
+
+ private static final String DEFAULT_OPENID_URL = "https://api.openai.com";
+ private HttpClient> httpClient;
+ private String url = DEFAULT_OPENID_URL;
+ private String apiKey;
+
+ private Builder() {
+ }
+
+ @Override
+ public OpenAIChatModel build() {
+ Objects.requireNonNull(apiKey, "OpenAI API key is mandatory.");
+ Objects.requireNonNull(httpClient, "HttpClient is mandatory to make HTTP requests to OpenAI.");
+ URI uri = URI.create(url + "/v1/chat/completions");
+ return new OpenAIChatModel(httpClient, uri, apiKey);
+ }
+
+ /**
+ * Configure http client for HTTP requests, so multiple instances of {@link OpenAIChatModel} can
+ * re-use the same client for performance reasons.
+ * The client will never be closed by {@link OpenAIChatModel}.
+ *
+ * @param httpClient the configured HTTP Client
+ * @return updated builder instance
+ */
+ public Builder client(HttpClient> httpClient) {
+ this.httpClient = httpClient;
+ return this;
+ }
+
+ /**
+ * The URL of OpenAI. It defaults to {@link #DEFAULT_OPENID_URL}.
+ *
+ * @param url of OpenAI
+ * @return updated builder instance
+ */
+ public Builder url(String url) {
+ this.url = url;
+ return this;
+ }
+
+ /**
+ * Configure the API key to authenticate with OpenAI.
+ *
+ * @param apiKey
+ * @return updated builder instance
+ */
+ public Builder apiKey(String apiKey) {
+ this.apiKey = apiKey;
+ return this;
+ }
+ }
+
+}
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChoice.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChoice.java
new file mode 100644
index 00000000000..b96efeef54a
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIChoice.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.io.Serializable;
+
+/**
+ * Represents a choice made by OpenAI.
+ * This class encapsulates the index of the choice, the message associated with the choice,
+ * and the reason why the choice was finished.
+ * It implements {@link Serializable} for object serialization.
+ *
+ */
+public class OpenAIChoice implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private int index;
+ private OpenAIMessage message;
+ private String finish_reason;
+
+ /**
+ * Required public constructor.
+ */
+ public OpenAIChoice() {
+ }
+
+ /**
+ * Gets the index of the choice.
+ *
+ * @return the index of the choice.
+ */
+ public int getIndex() {
+ return index;
+ }
+
+ /**
+ * Sets the index of the choice.
+ *
+ * @param index the index of the choice.
+ */
+ public void setIndex(int index) {
+ this.index = index;
+ }
+
+ /**
+ * Gets the message associated with the choice.
+ *
+ * @return the message associated with the choice.
+ */
+ public OpenAIMessage getMessage() {
+ return message;
+ }
+
+ /**
+ * Sets the message associated with the choice.
+ *
+ * @param message the message associated with the choice.
+ */
+ public void setMessage(OpenAIMessage message) {
+ this.message = message;
+ }
+
+ /**
+ * Gets the reason why the choice was finished.
+ *
+ * @return the reason why the choice was finished.
+ */
+ public String getFinish_reason() {
+ return finish_reason;
+ }
+
+ /**
+ * Sets the reason why the choice was finished.
+ *
+ * @param finish_reason the reason why the choice was finished.
+ */
+ public void setFinish_reason(String finish_reason) {
+ this.finish_reason = finish_reason;
+ }
+
+}
+
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIMessage.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIMessage.java
new file mode 100644
index 00000000000..4dc97432e21
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIMessage.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.io.Serializable;
+
+/**
+ * Represents a message in the OpenAI context.
+ * This class encapsulates the role and content of a message.
+ * It implements {@link Serializable} for object serialization.
+ *
+ */
+public class OpenAIMessage implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private String role;
+ private String content;
+
+ /**
+ * Required public constructor.
+ */
+ public OpenAIMessage() {
+ }
+
+ /**
+ * Gets the role of the message sender.
+ *
+ * @return the role of the message sender.
+ */
+ public String getRole() {
+ return role;
+ }
+
+ /**
+ * Sets the role of the message sender.
+ *
+ * @param role the role of the message sender.
+ */
+ public void setRole(String role) {
+ this.role = role;
+ }
+
+ /**
+ * Gets the content of the message.
+ *
+ * @return the content of the message.
+ */
+ public String getContent() {
+ return content;
+ }
+
+ /**
+ * Sets the content of the message.
+ *
+ * @param content the content of the message.
+ */
+ public void setContent(String content) {
+ this.content = content;
+ }
+}
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIRequest.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIRequest.java
new file mode 100644
index 00000000000..ced1852af7b
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIRequest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Represents a request to the OpenAI API.
+ * This class encapsulates the model to be used and the list of messages included in the request.
+ * It implements {@link Serializable} for object serialization.
+ *
+ */
+public class OpenAIRequest implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private static final String DEFAULT_OPENID_MODEL = "gpt-4o";
+ private String model = DEFAULT_OPENID_MODEL;
+ private List messages = List.of();
+
+ /**
+ * Required public constructor.
+ */
+ public OpenAIRequest() {
+ }
+
+ /**
+ * Gets the model to be used for the request.
+ * The default model is "gpt-4o".
+ *
+ * @return the model to be used for the request.
+ */
+ public String getModel() {
+ return model;
+ }
+
+ /**
+ * Sets the model to be used for the request.
+ *
+ * @param model the model to be used for the request.
+ */
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ /**
+ * Gets the list of messages included in the request.
+ *
+ * @return the list of messages included in the request.
+ */
+ public List getMessages() {
+ return messages;
+ }
+
+ /**
+ * Sets the list of messages included in the request.
+ *
+ * @param messages the list of messages included in the request.
+ */
+ public void setMessages(List messages) {
+ this.messages = messages;
+ }
+}
+
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIResponse.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIResponse.java
new file mode 100644
index 00000000000..91cc5adbaf9
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIResponse.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * Represents a response from the OpenAI API.
+ * This class encapsulates various details about the response such as
+ * the ID, object type, creation timestamp, model used, system fingerprint,
+ * finish reason, choices made, and usage statistics.
+ * It implements {@link Serializable} for object serialization.
+ *
+ */
+public class OpenAIResponse implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private String id;
+ private String object;
+ private long created;
+ private String model;
+ private String system_fingerprint;
+ private String finish_reason;
+ private List choices = List.of();
+ private OpenAIUsage usage;
+
+ /**
+ * Required public constructor.
+ */
+ public OpenAIResponse() {
+ }
+
+ /**
+ * Gets the ID of the response.
+ *
+ * @return the ID of the response.
+ */
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Sets the ID of the response.
+ *
+ * @param id the ID of the response.
+ */
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ /**
+ * Gets the object type of the response.
+ *
+ * @return the object type of the response.
+ */
+ public String getObject() {
+ return object;
+ }
+
+ /**
+ * Sets the object type of the response.
+ *
+ * @param object the object type of the response.
+ */
+ public void setObject(String object) {
+ this.object = object;
+ }
+
+ /**
+ * Gets the creation timestamp of the response.
+ *
+ * @return the creation timestamp of the response.
+ */
+ public long getCreated() {
+ return created;
+ }
+
+ /**
+ * Sets the creation timestamp of the response.
+ *
+ * @param created the creation timestamp of the response.
+ */
+ public void setCreated(long created) {
+ this.created = created;
+ }
+
+ /**
+ * Gets the model used to generate the response.
+ *
+ * @return the model used to generate the response.
+ */
+ public String getModel() {
+ return model;
+ }
+
+ /**
+ * Sets the model used to generate the response.
+ *
+ * @param model the model used to generate the response.
+ */
+ public void setModel(String model) {
+ this.model = model;
+ }
+
+ /**
+ * Gets the system fingerprint of the response.
+ *
+ * @return the system fingerprint of the response.
+ */
+ public String getSystem_fingerprint() {
+ return system_fingerprint;
+ }
+
+ /**
+ * Sets the system fingerprint of the response.
+ *
+ * @param system_fingerprint the system fingerprint of the response.
+ */
+ public void setSystem_fingerprint(String system_fingerprint) {
+ this.system_fingerprint = system_fingerprint;
+ }
+
+ /**
+ * Gets the reason why the response was finished.
+ *
+ * @return the reason why the response was finished.
+ */
+ public String getFinish_reason() {
+ return finish_reason;
+ }
+
+ /**
+ * Sets the reason why the response was finished.
+ *
+ * @param finish_reason the reason why the response was finished.
+ */
+ public void setFinish_reason(String finish_reason) {
+ this.finish_reason = finish_reason;
+ }
+
+ /**
+ * Gets the list of choices included in the response.
+ *
+ * @return the list of choices included in the response.
+ */
+ public List getChoices() {
+ return choices;
+ }
+
+ /**
+ * Sets the list of choices included in the response.
+ *
+ * @param choices the list of choices included in the response.
+ */
+ public void setChoices(List choices) {
+ this.choices = choices;
+ }
+
+ /**
+ * Gets the usage statistics of the response.
+ *
+ * @return the usage statistics of the response.
+ */
+ public OpenAIUsage getUsage() {
+ return usage;
+ }
+
+ /**
+ * Sets the usage statistics of the response.
+ *
+ * @param usage the usage statistics of the response.
+ */
+ public void setUsage(OpenAIUsage usage) {
+ this.usage = usage;
+ }
+}
+
diff --git a/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIUsage.java b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIUsage.java
new file mode 100644
index 00000000000..cd26e8aa5dc
--- /dev/null
+++ b/ia/openai/src/main/java/io/helidon/ia/openai/OpenAIUsage.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import java.io.Serializable;
+
+/**
+ * Represents the usage statistics for OpenAI.
+ * This class is used to keep track of token usage for prompts and completions.
+ * It implements {@link Serializable} for object serialization.
+ *
+ */
+public class OpenAIUsage implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+ private int prompt_tokens;
+ private int completion_tokens;
+ private int total_tokens;
+
+ /**
+ * Required public constructor.
+ */
+ public OpenAIUsage() {
+ }
+
+ /**
+ * Gets the number of tokens used for the prompt.
+ *
+ * @return the number of prompt tokens.
+ */
+ public int getPrompt_tokens() {
+ return prompt_tokens;
+ }
+
+ /**
+ * Sets the number of tokens used for the prompt.
+ *
+ * @param prompt_tokens the number of prompt tokens.
+ */
+ public void setPrompt_tokens(int prompt_tokens) {
+ this.prompt_tokens = prompt_tokens;
+ }
+
+ /**
+ * Gets the number of tokens used for the completion.
+ *
+ * @return the number of completion tokens.
+ */
+ public int getCompletion_tokens() {
+ return completion_tokens;
+ }
+
+ /**
+ * Sets the number of tokens used for the completion.
+ *
+ * @param completion_tokens the number of completion tokens.
+ */
+ public void setCompletion_tokens(int completion_tokens) {
+ this.completion_tokens = completion_tokens;
+ }
+
+ /**
+ * Gets the total number of tokens used (prompt + completion).
+ *
+ * @return the total number of tokens.
+ */
+ public int getTotal_tokens() {
+ return total_tokens;
+ }
+
+ /**
+ * Sets the total number of tokens used (prompt + completion).
+ *
+ * @param total_tokens the total number of tokens.
+ */
+ public void setTotal_tokens(int total_tokens) {
+ this.total_tokens = total_tokens;
+ }
+}
\ No newline at end of file
diff --git a/ia/openai/src/main/java/module-info.java b/ia/openai/src/main/java/module-info.java
new file mode 100644
index 00000000000..619f2762945
--- /dev/null
+++ b/ia/openai/src/main/java/module-info.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * IA OpenId module.
+ *
+ */
+module io.helidon.ia.openai {
+
+ requires io.helidon.ia.api;
+ requires io.helidon.common;
+ requires io.helidon.webclient.api;
+ requires io.helidon.webclient.http1;
+
+}
\ No newline at end of file
diff --git a/ia/openai/src/test/java/io/helidon/ia/openai/OpenAIChatModelTest.java b/ia/openai/src/test/java/io/helidon/ia/openai/OpenAIChatModelTest.java
new file mode 100644
index 00000000000..04af52138ca
--- /dev/null
+++ b/ia/openai/src/test/java/io/helidon/ia/openai/OpenAIChatModelTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024 Oracle and/or its affiliates.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package io.helidon.ia.openai;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import io.helidon.http.HeaderNames;
+import io.helidon.http.Status;
+import io.helidon.webclient.api.ClientRequest;
+import io.helidon.webclient.api.HttpClient;
+import io.helidon.webclient.api.HttpClientResponse;
+
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+class OpenAIChatModelTest {
+
+ @Test
+ void testOK() {
+ HttpClient> httpClient = mockHttpClient(Status.OK_200);
+ OpenAIChatModel chatModel = OpenAIChatModel.create("api-key", httpClient);
+ OpenAIMessage message = new OpenAIMessage();
+ message.setContent("Say hello");
+ OpenAIRequest req = new OpenAIRequest();
+ req.setMessages(List.of(message));
+ chatModel.call(new OpenAIRequest());
+ }
+
+ @Test
+ void testNOK() {
+ HttpClient> httpClient = mockHttpClient(Status.UNAUTHORIZED_401);
+ OpenAIChatModel chatModel = OpenAIChatModel.create("api-key", httpClient);
+ OpenAIMessage message = new OpenAIMessage();
+ message.setContent("Say hello");
+ OpenAIRequest req = new OpenAIRequest();
+ req.setMessages(List.of(message));
+ assertThrows(IllegalStateException.class, () -> chatModel.call(new OpenAIRequest()));
+ }
+
+ private HttpClient> mockHttpClient(Status status) {
+ HttpClient> httpClient = Mockito.mock(HttpClient.class);
+ ClientRequest> request = Mockito.mock(ClientRequest.class);
+ HttpClientResponse response = Mockito.mock(HttpClientResponse.class);
+ doReturn(request).when(httpClient).post(anyString());
+ doReturn(request).when(request).header(eq(HeaderNames.CONTENT_TYPE), anyString());
+ doReturn(request).when(request).header(eq(HeaderNames.AUTHORIZATION), anyString());
+ doReturn(response).when(request).submit(any(OpenAIRequest.class));
+ when(response.status()).thenReturn(status);
+ return httpClient;
+ }
+}
diff --git a/ia/pom.xml b/ia/pom.xml
new file mode 100644
index 00000000000..3d85303738f
--- /dev/null
+++ b/ia/pom.xml
@@ -0,0 +1,40 @@
+
+
+
+
+ 4.0.0
+
+ io.helidon
+ helidon-project
+ 4.1.0-SNAPSHOT
+
+
+ io.helidon.ia
+ helidon-ia-project
+ Helidon IA Project
+
+ pom
+
+
+ api
+ openai
+
+
diff --git a/pom.xml b/pom.xml
index ca3cf682537..89ca3004f41 100644
--- a/pom.xml
+++ b/pom.xml
@@ -207,6 +207,7 @@
health
helidon
http
+ ia
inject
integrations
jersey