Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-03 Thread via GitHub


devmadhuu commented on PR #9915:
URL: https://github.com/apache/ozone/pull/9915#issuecomment-4614654457

   @ArafatKhan2198 though PR is merged by you, but as discussed, I still don't 
see any test if chatbot is functional in secure cluster which is bare minimum 
requirement.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-02 Thread via GitHub


adoroszlai commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3346138376


##
hadoop-ozone/dist/src/main/license/bin/LICENSE.txt:
##
@@ -261,6 +261,21 @@ CDDL 1.1 + GPLv2 with classpath exception
org.glassfish.jaxb:txw2
 
 
+Apache License 2.0
+=
+   com.squareup.okhttp3:okhttp
+   com.squareup.okhttp3:okhttp-sse
+   com.squareup.okio:okio
+   com.squareup.retrofit2:converter-jackson
+   com.squareup.retrofit2:retrofit
+   dev.ai4j:openai4j
+   dev.langchain4j:langchain4j-anthropic
+   dev.langchain4j:langchain4j-core
+   dev.langchain4j:langchain4j-open-ai
+   org.jetbrains.kotlin:kotlin-stdlib-common
+   org.jetbrains.kotlin:kotlin-stdlib-jdk7
+   org.jetbrains.kotlin:kotlin-stdlib-jdk8
+
 Apache License 2.0
 =

Review Comment:
   Created HDDS-15469 for this.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-02 Thread via GitHub


adoroszlai commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3346119890


##
pom.xml:
##
@@ -1656,6 +1675,57 @@
 snakeyaml
 ${snakeyaml.version}
   
+  
+
+software.amazon.awssdk
+apache-client
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+auth
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+aws-core
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+http-client-spi
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+identity-spi
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+regions
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+s3
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+s3-transfer-manager
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+sdk-core
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+utils
+${aws-java-sdk2.version}
+  

Review Comment:
   This will also be fixed in #10421.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-02 Thread via GitHub


adoroszlai commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3346119125


##
pom.xml:
##
@@ -1601,6 +1609,17 @@
 jooq-meta
 ${jooq.version}
   
+  
+
+org.junit.jupiter
+junit-jupiter-api
+${junit5.version}
+  
+  
+org.junit.jupiter
+junit-jupiter-params
+${junit5.version}
+  

Review Comment:
   This will be fixed in #10421.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-02 Thread via GitHub


adoroszlai commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3340978215


##
hadoop-ozone/dist/src/main/license/jar-report.txt:
##
@@ -2,14 +2,14 @@ share/ozone/lib/aircompressor.jar
 share/ozone/lib/animal-sniffer-annotations.jar
 share/ozone/lib/annotations.jar
 share/ozone/lib/annotations.jar
-share/ozone/lib/apache-log4j-extras.jar
-share/ozone/lib/aopalliance.jar
 share/ozone/lib/aopalliance-repackaged.jar
+share/ozone/lib/aopalliance.jar
+share/ozone/lib/apache-log4j-extras.jar

Review Comment:
   Please don't move around lines unnecessarily.



##
hadoop-ozone/dist/src/main/compose/ozone/docker-config:
##
@@ -23,7 +23,7 @@ CORE-SITE.XML_hadoop.proxyuser.hadoop.groups=*
 OZONE-SITE.XML_ozone.om.address=om
 OZONE-SITE.XML_ozone.om.http-address=om:9874
 OZONE-SITE.XML_ozone.scm.http-address=scm:9876
-OZONE-SITE.XML_ozone.scm.container.size=100MB
+OZONE-SITE.XML_ozone.scm.container.size=1GB

Review Comment:
   Why was this changed?  We use a small value to reduce chances of disk out of 
space error in acceptance tests.



##
hadoop-ozone/dist/src/main/license/bin/LICENSE.txt:
##
@@ -261,6 +261,21 @@ CDDL 1.1 + GPLv2 with classpath exception
org.glassfish.jaxb:txw2
 
 
+Apache License 2.0
+=
+   com.squareup.okhttp3:okhttp
+   com.squareup.okhttp3:okhttp-sse
+   com.squareup.okio:okio
+   com.squareup.retrofit2:converter-jackson
+   com.squareup.retrofit2:retrofit
+   dev.ai4j:openai4j
+   dev.langchain4j:langchain4j-anthropic
+   dev.langchain4j:langchain4j-core
+   dev.langchain4j:langchain4j-open-ai
+   org.jetbrains.kotlin:kotlin-stdlib-common
+   org.jetbrains.kotlin:kotlin-stdlib-jdk7
+   org.jetbrains.kotlin:kotlin-stdlib-jdk8
+
 Apache License 2.0
 =

Review Comment:
   Please don't duplicate License sections, add the dependencies in existing 
sections in alphabetical order.



##
pom.xml:
##
@@ -1601,6 +1609,17 @@
 jooq-meta
 ${jooq.version}
   
+  
+
+org.junit.jupiter
+junit-jupiter-api
+${junit5.version}
+  
+  
+org.junit.jupiter
+junit-jupiter-params
+${junit5.version}
+  

Review Comment:
   We already import `junit-bom`.
   
   
https://github.com/apache/ozone/blob/2020d864c78c90582f9f3f661ea98a49cb51e608/pom.xml#L300-L306



##
pom.xml:
##
@@ -1656,6 +1675,57 @@
 snakeyaml
 ${snakeyaml.version}
   
+  
+
+software.amazon.awssdk
+apache-client
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+auth
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+aws-core
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+http-client-spi
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+identity-spi
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+regions
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+s3
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+s3-transfer-manager
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+sdk-core
+${aws-java-sdk2.version}
+  
+  
+software.amazon.awssdk
+utils
+${aws-java-sdk2.version}
+  

Review Comment:
   These are unnecessary.  AWS SDK v2 is only used in tests and that module 
uses the BOM:
   
   
https://github.com/apache/ozone/blob/2020d864c78c90582f9f3f661ea98a49cb51e608/hadoop-ozone/integration-test-s3/pom.xml#L29-L30



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-02 Thread via GitHub


ArafatKhan2198 merged PR #9915:
URL: https://github.com/apache/ozone/pull/9915


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-01 Thread via GitHub


ArafatKhan2198 commented on PR #9915:
URL: https://github.com/apache/ozone/pull/9915#issuecomment-4599559387

   ## Green Run - 
https://github.com/ArafatKhan2198/ozone/actions/runs/26800762880


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-01 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r468255


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/ChatbotConfigKeys.java:
##
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hadoop.ozone.recon.chatbot;
+
+import org.apache.hadoop.hdds.annotation.InterfaceAudience;
+import org.apache.hadoop.hdds.annotation.InterfaceStability;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+
+/**
+ * Configuration keys for Recon Chatbot service.
+ */
[email protected]
[email protected]
+public final class ChatbotConfigKeys {
+
+  public static final String OZONE_RECON_CHATBOT_PREFIX = 
"ozone.recon.chatbot.";
+
+  // ── Feature toggle ──
+  public static final String OZONE_RECON_CHATBOT_ENABLED = 
OZONE_RECON_CHATBOT_PREFIX + "enabled";
+  public static final boolean OZONE_RECON_CHATBOT_ENABLED_DEFAULT = false;
+
+  // ── Provider selection ──
+  /**
+   * Active default provider: openai, gemini, anthropic.
+   */
+  public static final String OZONE_RECON_CHATBOT_PROVIDER = 
OZONE_RECON_CHATBOT_PREFIX + "provider";
+  public static final String OZONE_RECON_CHATBOT_PROVIDER_DEFAULT = "gemini";
+
+  // ── Default model ───
+  public static final String OZONE_RECON_CHATBOT_DEFAULT_MODEL = 
OZONE_RECON_CHATBOT_PREFIX + "default.model";
+  public static final String OZONE_RECON_CHATBOT_DEFAULT_MODEL_DEFAULT = 
"gemini-2.5-flash";
+
+  // ── HTTP timeout for provider calls ─
+  public static final String OZONE_RECON_CHATBOT_TIMEOUT_MS = 
OZONE_RECON_CHATBOT_PREFIX + "timeout.ms";
+  public static final int OZONE_RECON_CHATBOT_TIMEOUT_MS_DEFAULT = 12;
+
+  // ── Per-provider API keys (resolved via JCEKS / CredentialHelper) ──
+  public static final String OZONE_RECON_CHATBOT_OPENAI_API_KEY = 
OZONE_RECON_CHATBOT_PREFIX + "openai.api.key";
+  public static final String OZONE_RECON_CHATBOT_GEMINI_API_KEY = 
OZONE_RECON_CHATBOT_PREFIX + "gemini.api.key";
+  public static final String OZONE_RECON_CHATBOT_ANTHROPIC_API_KEY = 
OZONE_RECON_CHATBOT_PREFIX
+  + "anthropic.api.key";
+
+  // ── Per-provider base URL overrides (optional) ──
+  public static final String OZONE_RECON_CHATBOT_OPENAI_BASE_URL = 
OZONE_RECON_CHATBOT_PREFIX + "openai.base.url";
+  public static final String OZONE_RECON_CHATBOT_OPENAI_BASE_URL_DEFAULT = 
"https://api.openai.com";;
+
+  // ── Execution policy 
+  public static final String OZONE_RECON_CHATBOT_EXEC_MAX_RECORDS = 
OZONE_RECON_CHATBOT_PREFIX
+  + "exec.max.records";

Review Comment:
   If this is really needed.



##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ToolExecutor.java:
##
@@ -0,0 +1,373 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.Ht

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-06-01 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r126609


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LangChain4jDispatcher.java:
##
@@ -0,0 +1,414 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import dev.langchain4j.model.output.TokenUsage;
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link LLMClient} implementation backed by
+ * https://github.com/langchain4j/langchain4j";>LangChain4j.
+ *
+ * This is the only class in the chatbot that knows about LangChain4j. It 
resolves the
+ * correct provider for a given model, builds a {@link ChatLanguageModel}, 
translates the
+ * message list into LangChain4j types, fires the completion, and returns a 
normalised
+ * {@link LLMResponse}. Everything above this class ({@code ChatbotAgent},
+ * {@code ChatbotEndpoint}) depends only on the {@link LLMClient} 
interface.
+ *
+ * Startup: reads configuration and checks which providers have API 
keys. No
+ * network calls are made until {@link #chatCompletion} is first invoked.
+ *
+ * Provider routing — resolved in this order on every call:
+ * 
+ *   Explicit {@code _provider} key in the parameters map, or a {@code 
provider:model}
+ *   prefix in the model string.
+ *   Reverse lookup in the configured model lists ({@link 
#supportedModels}): the same
+ *   map that drives {@code GET /chatbot/models}. Adding a model to
+ *   {@code ozone.recon.chatbot.openai.models} in {@code ozone-site.xml} 
makes it
+ *   routable with no code change.
+ *   If the model is not found and no hint was given, {@link LLMException} 
is thrown
+ *   directing the caller to {@code GET /api/v1/chatbot/models}.
+ * 
+ *
+ * Model caching: building a {@link ChatLanguageModel} creates an 
HTTP client and
+ * SSL context, so each {@code (provider, model)} pair is built once and 
cached in
+ * {@link #modelCache}. If the first call with that model fails, the entry is 
evicted so a
+ * bad model name cannot get stuck in the cache permanently.
+ */
+@Singleton
+public class LangChain4jDispatcher implements LLMClient {
+
+  private static final Logger LOG =
+  LoggerFactory.getLogger(LangChain4jDispatcher.class);
+
+  private final OzoneConfiguration configuration;
+  private final CredentialHelper credentialHelper;
+  private final Duration timeout;
+  private final String defaultProvider;
+
+  /**
+   * Per-provider static model lists — used by getSupportedModels() and 
isAvailable().
+   * A provider only appears here if its API key is configured.
+   */
+  private final Map> supportedModels = new HashMap<>();
+
+  /**
+   * Cache of built {@link ChatLanguageModel} instances, keyed by {@code 
"provider:model"}.
+   *
+   * Building a model involves constructing an HTTP client, SSL context, 
and connection pool —
+   * expensive operations that should happen once, not on every request. This 
cache ensures each
+   * (provider, model) pair is built exactly once and then reused for all 
subsequent calls.
+   *
+   * {@link ConcurrentHashMap} is used because multiple chatbot executor 
threads may call
+   * {@link 

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-29 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3325061227


##
hadoop-ozone/recon/src/main/resources/chatbot/recon-fallback-prompt-template.txt:
##


Review Comment:
   I tried to avoid adding license headers to these files, as the raw text is 
fed directly to the LLM and the header might interfere with the prompts. 
Instead, I have added it to rat-exclusions.txt to exclude the chatbot resources 
directory from the RAT check.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-29 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3325028303


##
hadoop-ozone/recon/pom.xml:
##
@@ -62,6 +62,22 @@
   commons-io
   commons-io
 
+
+  dev.langchain4j
+  langchain4j-anthropic
+
+
+  dev.langchain4j
+  langchain4j-core
+

Review Comment:
   Done. I've updated both jar-report.txt and LICENSE.txt to include the new 
transitive dependencies introduced by LangChain4j (such as jtokkit, okhttp, 
retrofit, and kotlin-stdlib).
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-29 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3325026354


##
pom.xml:
##
@@ -569,6 +569,26 @@
   
 
   
+  
+dev.langchain4j
+langchain4j-anthropic
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-core
+0.36.2

Review Comment:
   Thanks for pointing this out. LangChain4j officially dropped Java 8 support 
starting with 0.36.0.
   
   I have downgraded the langchain4j.version to 0.35.0. This is the latest 
release that should compiles to Java 8.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-28 Thread via GitHub


adoroszlai commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3319512100


##
pom.xml:
##
@@ -515,6 +569,26 @@
   
 
   
+  
+dev.langchain4j
+langchain4j-anthropic
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-core
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-google-ai-gemini
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-open-ai
+0.36.2
+  

Review Comment:
   > every other third-party library in the project follows this same pattern 
of individual version entries. Introducing a BOM import for just this one 
library would be inconsistent with how the rest of the project is structured.
   
   1. BOM import has been in use for quite some time now, so please do switch 
to `langchain4j-bom`:
   
https://github.com/apache/ozone/blob/cfb8adea488da08a56f75acf46011574325482aa/pom.xml#L229-L327
   2. Even if BOM is not available for some dependency, please define a 
property for consistent versioning of multi-module dependency, example:
   
https://github.com/apache/ozone/blob/cfb8adea488da08a56f75acf46011574325482aa/pom.xml#L517-L526



##
hadoop-ozone/recon/pom.xml:
##
@@ -62,6 +62,22 @@
   commons-io
   commons-io
 
+
+  dev.langchain4j
+  langchain4j-anthropic
+
+
+  dev.langchain4j
+  langchain4j-core
+

Review Comment:
   ```
   Jar files under share/ozone/lib in the build have changed.
   
   Please update:
   
* hadoop-ozone/dist/src/main/license/bin/LICENSE.txt
  (add new dependencies with the appropriate license, delete any removed 
dependencies)
   
* hadoop-ozone/dist/src/main/license/jar-report.txt
  (based on the diff shown below)
   
   If you notice unexpected differences (can happen when the check is run in a
   fork), please first update your branch from upstream master to get any other
   recent dependency changes.
   
   If you are running this locally after build with -DskipShade, please ignore 
any
   ozone-filesystem jars reported to be missing.
   
   Changes detected:
   
   --- /dev/fd/63   2026-05-27 10:02:54.566056827 +
   +++ /dev/fd/62   2026-05-27 10:02:54.566056827 +
   @@ -35,6 +35,7 @@
share/ozone/lib/commons-pool2.jar
share/ozone/lib/commons-text.jar
share/ozone/lib/commons-validator.jar
   +share/ozone/lib/converter-jackson.jar
share/ozone/lib/curator-client.jar
share/ozone/lib/curator-framework.jar
share/ozone/lib/derby.jar
   @@ -158,6 +159,7 @@
share/ozone/lib/jsp-api.jar
share/ozone/lib/jspecify.jar
share/ozone/lib/jsr311-api.jar
   +share/ozone/lib/jtokkit.jar
share/ozone/lib/kerb-core.jar
share/ozone/lib/kerb-crypto.jar
share/ozone/lib/kerb-util.jar
   @@ -165,7 +167,14 @@
share/ozone/lib/kerby-config.jar
share/ozone/lib/kerby-pkix.jar
share/ozone/lib/kerby-util.jar
   +share/ozone/lib/kotlin-stdlib-common.jar
   +share/ozone/lib/kotlin-stdlib-jdk7.jar
   +share/ozone/lib/kotlin-stdlib-jdk8.jar
share/ozone/lib/kotlin-stdlib.jar
   +share/ozone/lib/langchain4j-anthropic.jar
   +share/ozone/lib/langchain4j-core.jar
   +share/ozone/lib/langchain4j-google-ai-gemini.jar
   +share/ozone/lib/langchain4j-open-ai.jar
share/ozone/lib/listenablefuture-empty-to-avoid-conflict-with-guava.jar
share/ozone/lib/log4j-api.jar
share/ozone/lib/log4j-core.jar
   @@ -193,7 +202,11 @@
share/ozone/lib/netty-transport.Final.jar
share/ozone/lib/nimbus-jose-jwt.jar
share/ozone/lib/okhttp-jvm.jar
   +share/ozone/lib/okhttp-sse.jar
   +share/ozone/lib/okhttp.jar
share/ozone/lib/okio-jvm.jar
   +share/ozone/lib/okio.jar
   +share/ozone/lib/openai4j.jar
share/ozone/lib/opentelemetry-api.jar
share/ozone/lib/opentelemetry-common.jar
share/ozone/lib/opentelemetry-context.jar
   @@ -259,6 +272,7 @@
share/ozone/lib/re2j.jar
share/ozone/lib/reflections.jar
share/ozone/lib/reload4j.jar
   +share/ozone/lib/retrofit.jar
share/ozone/lib/rocksdb-checkpoint-differ.jar
share/ozone/lib/rocksdbjni.jar
share/ozone/lib/simpleclient.jar
   
   ```
   
   
https://github.com/ArafatKhan2198/ozone/actions/runs/26503992485/job/78053259617#step:13:18



##
hadoop-ozone/recon/src/main/resources/chatbot/recon-fallback-prompt-template.txt:
##


Review Comment:
   ```
   Files with unapproved licenses:
 
/home/runner/work/ozone/ozone/hadoop-ozone/recon/src/main/resources/chatbot/recon-summarization-prompt.txt
 
/home/runner/work/ozone/ozone/hadoop-ozone/recon/src/main/resources/chatbot/recon-fallback-prompt-template.txt
 
/home/runner/work/ozone/ozone/hadoop-ozone/recon/src/main/resources/chatbot/recon-api-guide.md
 
/home/runner/work/ozone/ozone/hadoop-ozone/recon/src/main/resources/chatbot/recon-tool-selection-prompt-preamble.txt
   ```



##
pom.xml:
##

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-20 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3273813427


##
hadoop-ozone/recon/src/test/java/org/apache/hadoop/ozone/recon/chatbot/llm/TestLLMDispatcher.java:
##
@@ -0,0 +1,191 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests for {@link LangChain4jDispatcher}.
+ *
+ * These tests exercise routing (which provider is selected for a given 
model name)
+ * and availability checking without making any real network calls.
+ * All tests that verify provider routing do so by confirming the correct 
provider name
+ * appears in the exception message thrown when no API key is configured — 
this is the
+ * cheapest way to prove the routing decision without mocking the LangChain4j 
internals.
+ */
+public class TestLLMDispatcher {

Review Comment:
   We can rename this class to TestLangChain4jDispatcher



##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,773 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);

Review Comment:
   It will misparse any LLM response containing reasoning text alongside the 
JSON, or any JSON value containing a closing brace. Can you unit test this by 
passing a hardcoded LLM response where if reasoning text also there along with 
JSON 

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-19 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264703839


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LangChain4jDispatcher.java:
##
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import dev.langchain4j.model.output.TokenUsage;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link LLMClient} implementation that sends chat requests to cloud LLM 
providers using
+ * https://github.com/langchain4j/langchain4j";>LangChain4j.
+ *
+ * Purpose
+ * The Recon chatbot needs to call external APIs (OpenAI, Google Gemini, 
Anthropic Claude)
+ * with a stable Java contract. This class is the only place that talks to 
LangChain4j: it
+ * picks the right provider, builds a {@link ChatLanguageModel} for the 
requested model,
+ * converts messages into LangChain4j types, runs one completion, and maps the 
result back to
+ * {@link LLMResponse}. Higher layers ({@link 
org.apache.hadoop.ozone.recon.chatbot.agent.ChatbotAgent},
+ * {@link org.apache.hadoop.ozone.recon.chatbot.api.ChatbotEndpoint}) depend 
only on {@link LLMClient}.
+ *
+ * Lifecycle (no background work)
+ * The class is registered in Guice as a singleton: one instance exists for 
the whole Recon process.
+ * There is no timer, no scheduled task, and no long-lived outbound 
connection. At startup
+ * the constructor only reads configuration and records which providers have 
API keys (for
+ * {@link #isAvailable()} and {@link #getSupportedModels()}). Actual network 
calls happen
+ * only when {@link #chatCompletion} runs on an HTTP request thread.
+ *
+ * Request flow (one chat completion)
+ * Each user message is handled synchronously on the thread that serves the 
REST call:
+ * 
+ * User HTTP request
+ * |
+ * v
+ * Jersey dispatches to ChatbotEndpoint (request thread)
+ * |
+ * v
+ * ChatbotAgent orchestrates tool selection / summarization
+ * |
+ * v
+ * LangChain4jDispatcher.chatCompletion(...)
+ * |
+ * +-- Resolve provider (see below)
+ * |
+ * +-- Build a new ChatLanguageModel for that provider + model name 
(configuration only)
+ * |
+ * +-- Translate ChatMessage list to LangChain4j messages (system / 
user / assistant)
+ * |
+ * +-- chatModel.chat(ChatRequest)  --> outbound HTTPS to the 
vendor (may take seconds)
+ * |
+ * v
+ * LLMResponse returned to the agent, then JSON to the client
+ * 
+ *
+ * How provider routing works
+ * When {@link #chatCompletion} runs, the provider is chosen in this 
order:
+ * 
+ *   Optional {@code _provider} entry in the parameters map (e.g. {@code 
"gemini"}).
+ *   If the model string looks like {@code provider:model}, the prefix 
before {@code :}
+ *   is the provider.
+ *   Otherwise the model name: {@code gpt-} / {@code o1} / {@code o3} → 
{@code openai};
+ *   {@code gemini} → {@code gemini}; {@code claude} → {@code 
anthropic}.
+ *   If still unclear, {@link 
ChatbotConfigKeys#OZONE_RECON_CHATBOT_PROVIDER} is used.
+ * 
+ * For each call, a fresh {@link ChatLanguageModel} is built with the exact 
model id the
+ * caller passed (for example 

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-19 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264702033


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconControllerModule.java:
##
@@ -131,6 +131,12 @@ protected void configure() {
 install(new ReconOmTaskBindingModule());
 install(new ReconDaoBindingModule());
 bind(ReconTaskStatusUpdaterManager.class).in(Singleton.class);
+// Only install chatbot bindings when the feature is explicitly enabled.
+// This prevents startup-time failures (e.g. bad credential provider paths)
+// from breaking Recon when the chatbot is intentionally disabled.
+if (ChatbotConfigKeys.isChatbotEnabled(new ConfigurationProvider().get())) 
{

Review Comment:
   Done. Added getConf() on ReconServer and changed the guard to 
ChatbotConfigKeys.isChatbotEnabled(reconServer.getConf()) so we use the config 
from the server instance already held by ReconControllerModule instead of going 
through ConfigurationProvider.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-19 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264699690


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,800 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotException;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final String LIST_KEYS_ENDPOINT_SUFFIX = "/keys/listKeys";
+
+  /**
+   * Allowlist of Recon API path prefixes the chatbot is permitted to call.
+   *
+   * This is the primary defence against prompt injection: even if an attacker 
tricks
+   * the LLM into outputting an arbitrary endpoint, the Java layer will reject 
it here
+   * before ToolExecutor makes any network call. Only paths listed here can 
ever be
+   * executed. The check uses prefix matching so that parameterised paths like
+   * /api/v1/containers/unhealthy/MISSING are covered by the 
/api/v1/containers entry.
+   */
+  private static final Set ALLOWED_ENDPOINT_PREFIXES =
+  Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+  "/api/v1/clusterState",
+  "/api/v1/datanodes",
+  "/api/v1/pipelines",
+  "/api/v1/containers",
+  "/api/v1/keys",
+  "/api/v1/volumes",
+  "/api/v1/buckets",
+  "/api/v1/task/status",
+  "/api/v1/metrics",
+  "/api/v1/utilization",
+  "/api/v1/namespace",
+  "/api/v1/om"
+  )));
+
+  // The connection to Gemini/OpenAI
+  private final LLMClient llmClient;
+
+  // The hands that execute the internal API calls
+  private final ToolExecutor toolExecutor;
+
+  // The Cheat Sheet of all available APIs loaded from the .md file
+  private final String apiSchema;
+
+  // Prompt preamble for tool selection — loaded from classpath resource
+  private final String toolSelectionPreamble;
+
+  // System prompt for the summarization LLM call — loaded from classpath 
resource
+  private final String summarizationPrompt;
+
+  // Template for the fallback response when no endpoint matches — loaded from 
classpath resource
+  private final String fallbackPromptTemplate;
+
+  // Max API calls we allow per question (so the LLM doesn't DOS our server)
+  private final int maxToolCalls;
+
+
+  private final String defaultModel;
+  private final int maxRecordsPerAnswer;
+  private final int maxPagesPerAnswer;
+  private final int pageSizePerCall;
+  private final boolean requireSafeScope;
+
+  @Inject
+  public ChatbotAgent(LLMClient llmClient,
+   

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-19 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264705458


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,773 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);

Review Comment:
   Resolved. Removed JSON_PATTERN and added extractFirstJsonObject(), which 
uses brace-depth counting with string-awareness (ignores {/} inside quoted 
values, handles escapes). It returns the first complete outermost JSON object, 
so it works for SINGLE_ENDPOINT, MULTI_ENDPOINT (nested tool_calls), and 
DOCUMENTATION_QUERY, and when the LLM wraps JSON in prose.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-18 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264248935


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LLMClient.java:
##
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * LLMClient is the "Master Contract" for the whole Chatbot system.
+ * 
+ * Purpose:
+ * The ChatbotAgent doesn't know (or care) if it's talking to OpenAI, Gemini, 
or a Local LLM.
+ * It strictly relies on this interface. This interface forces every AI client 
to guarantee
+ * that they will accept exactly the same input and return exactly the same 
output.
+ * 
+ * By using this contract, we can add 10 new AI models to Recon tomorrow,
+ * and we will never have to edit the ChatbotAgent's code to support them!
+ */
+public interface LLMClient {
+
+  /**
+   * The core action: Send a conversation to an AI and wait for its answer.
+   *
+   * API keys are always resolved server-side via
+   * {@link org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper} 
from
+   * the Hadoop credential store or {@code ozone-site.xml}. There is no 
per-request
+   * key parameter — all callers should be cluster admins using the shared 
server key.
+   *
+   * @param messages   The back-and-forth chat history so far (System Prompts, 
User Questions, etc.)
+   * @param model  The specific model name (e.g. "gpt-4.1" or 
"gemini-2.5-flash")
+   * @param parameters Extra rules like "temperature" (how creative the AI 
should be) or
+   *   "max_tokens" (how long the answer can be)
+   * @return A standardized LLMResponse object containing the AI's final text.
+   * @throws LLMException if the network fails, the API key is missing, or the 
provider returns an error.
+   */
+  LLMResponse chatCompletion(
+  List messages,
+  String model,
+  Map parameters) throws LLMException;
+
+  /**
+   * Quick check to see if this client is ready to work (e.g., does it have an 
API key saved?)
+   */
+  boolean isAvailable();
+
+  /**
+   * Asks the AI client for a list of all the different models it supports 
right now.
+   * We use this to populate the drop-down menu in the user interface!
+   */
+  List getSupportedModels();
+
+  // =
+  // Data Transfer Objects (DTOs)
+  // These are the standardized containers we use to pass information around.
+  // =
+
+  /**
+   * A single message in a conversation.
+   * Every message needs a "role" (who is speaking: user or assistant) 
+   * and "content" (what they actually said).
+   */
+  class ChatMessage {
+private final String role;
+private final String content;
+
+public ChatMessage(String role, String content) {
+  this.role = role;
+  this.content = content;
+}
+
+public String getRole() {
+  return role;
+}
+
+public String getContent() {
+  return content;
+}
+  }
+
+  /**
+   * The standardized package that every AI MUST return when it finishes 
thinking.
+   * Instead of OpenAI returning one JSON format and Gemini returning a 
completely different one,
+   * our background code forces them both to output this clean Java object.
+   */
+  class LLMResponse {
+
+// The actual text the AI typed out
+private final String content;
+
+// Which AI model specifically answered this? (e.g. "gpt-4")
+private final String model;
+
+// How many "words" the user asked
+private final int promptTokens;
+
+// How many "words" the AI answered with
+private final int completionTokens;
+
+// Extra sneaky information about the answer (like why it stopped typing)
+private final Map metadata;
+
+public LLMResponse(String content, String model,
+   int promptTokens, int completionTokens,
+   Map metadata) {
+  this.content = content;
+  this.model = model;
+  this.promptTokens = promptTokens;
+  this.com

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-18 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264210827


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,800 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotException;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final String LIST_KEYS_ENDPOINT_SUFFIX = "/keys/listKeys";
+
+  /**
+   * Allowlist of Recon API path prefixes the chatbot is permitted to call.
+   *
+   * This is the primary defence against prompt injection: even if an attacker 
tricks
+   * the LLM into outputting an arbitrary endpoint, the Java layer will reject 
it here
+   * before ToolExecutor makes any network call. Only paths listed here can 
ever be
+   * executed. The check uses prefix matching so that parameterised paths like
+   * /api/v1/containers/unhealthy/MISSING are covered by the 
/api/v1/containers entry.
+   */
+  private static final Set ALLOWED_ENDPOINT_PREFIXES =
+  Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+  "/api/v1/clusterState",
+  "/api/v1/datanodes",
+  "/api/v1/pipelines",
+  "/api/v1/containers",
+  "/api/v1/keys",
+  "/api/v1/volumes",
+  "/api/v1/buckets",
+  "/api/v1/task/status",
+  "/api/v1/metrics",
+  "/api/v1/utilization",
+  "/api/v1/namespace",
+  "/api/v1/om"
+  )));
+
+  // The connection to Gemini/OpenAI
+  private final LLMClient llmClient;
+
+  // The hands that execute the internal API calls
+  private final ToolExecutor toolExecutor;
+
+  // The Cheat Sheet of all available APIs loaded from the .md file
+  private final String apiSchema;
+
+  // Prompt preamble for tool selection — loaded from classpath resource
+  private final String toolSelectionPreamble;
+
+  // System prompt for the summarization LLM call — loaded from classpath 
resource
+  private final String summarizationPrompt;
+
+  // Template for the fallback response when no endpoint matches — loaded from 
classpath resource
+  private final String fallbackPromptTemplate;
+
+  // Max API calls we allow per question (so the LLM doesn't DOS our server)
+  private final int maxToolCalls;
+
+
+  private final String defaultModel;
+  private final int maxRecordsPerAnswer;
+  private final int maxPagesPerAnswer;
+  private final int pageSizePerCall;
+  private final boolean requireSafeScope;
+
+  @Inject
+  public ChatbotAgent(LLMClient llmClient,
+   

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-18 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264058735


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LangChain4jDispatcher.java:
##
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import dev.langchain4j.model.output.TokenUsage;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link LLMClient} implementation that sends chat requests to cloud LLM 
providers using
+ * https://github.com/langchain4j/langchain4j";>LangChain4j.
+ *
+ * Purpose
+ * The Recon chatbot needs to call external APIs (OpenAI, Google Gemini, 
Anthropic Claude)
+ * with a stable Java contract. This class is the only place that talks to 
LangChain4j: it
+ * picks the right provider, builds a {@link ChatLanguageModel} for the 
requested model,
+ * converts messages into LangChain4j types, runs one completion, and maps the 
result back to
+ * {@link LLMResponse}. Higher layers ({@link 
org.apache.hadoop.ozone.recon.chatbot.agent.ChatbotAgent},
+ * {@link org.apache.hadoop.ozone.recon.chatbot.api.ChatbotEndpoint}) depend 
only on {@link LLMClient}.
+ *
+ * Lifecycle (no background work)
+ * The class is registered in Guice as a singleton: one instance exists for 
the whole Recon process.
+ * There is no timer, no scheduled task, and no long-lived outbound 
connection. At startup
+ * the constructor only reads configuration and records which providers have 
API keys (for
+ * {@link #isAvailable()} and {@link #getSupportedModels()}). Actual network 
calls happen
+ * only when {@link #chatCompletion} runs on an HTTP request thread.
+ *
+ * Request flow (one chat completion)
+ * Each user message is handled synchronously on the thread that serves the 
REST call:
+ * 
+ * User HTTP request
+ * |
+ * v
+ * Jersey dispatches to ChatbotEndpoint (request thread)
+ * |
+ * v
+ * ChatbotAgent orchestrates tool selection / summarization
+ * |
+ * v
+ * LangChain4jDispatcher.chatCompletion(...)
+ * |
+ * +-- Resolve provider (see below)
+ * |
+ * +-- Build a new ChatLanguageModel for that provider + model name 
(configuration only)
+ * |
+ * +-- Translate ChatMessage list to LangChain4j messages (system / 
user / assistant)
+ * |
+ * +-- chatModel.chat(ChatRequest)  --> outbound HTTPS to the 
vendor (may take seconds)
+ * |
+ * v
+ * LLMResponse returned to the agent, then JSON to the client
+ * 
+ *
+ * How provider routing works
+ * When {@link #chatCompletion} runs, the provider is chosen in this 
order:
+ * 
+ *   Optional {@code _provider} entry in the parameters map (e.g. {@code 
"gemini"}).
+ *   If the model string looks like {@code provider:model}, the prefix 
before {@code :}
+ *   is the provider.
+ *   Otherwise the model name: {@code gpt-} / {@code o1} / {@code o3} → 
{@code openai};
+ *   {@code gemini} → {@code gemini}; {@code claude} → {@code 
anthropic}.
+ *   If still unclear, {@link 
ChatbotConfigKeys#OZONE_RECON_CHATBOT_PROVIDER} is used.
+ * 
+ * For each call, a fresh {@link ChatLanguageModel} is built with the exact 
model id the
+ * caller passed (for example 

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-18 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3264041352


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LangChain4jDispatcher.java:
##
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import dev.langchain4j.model.output.TokenUsage;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link LLMClient} implementation that sends chat requests to cloud LLM 
providers using
+ * https://github.com/langchain4j/langchain4j";>LangChain4j.
+ *
+ * Purpose
+ * The Recon chatbot needs to call external APIs (OpenAI, Google Gemini, 
Anthropic Claude)
+ * with a stable Java contract. This class is the only place that talks to 
LangChain4j: it
+ * picks the right provider, builds a {@link ChatLanguageModel} for the 
requested model,
+ * converts messages into LangChain4j types, runs one completion, and maps the 
result back to
+ * {@link LLMResponse}. Higher layers ({@link 
org.apache.hadoop.ozone.recon.chatbot.agent.ChatbotAgent},
+ * {@link org.apache.hadoop.ozone.recon.chatbot.api.ChatbotEndpoint}) depend 
only on {@link LLMClient}.
+ *
+ * Lifecycle (no background work)
+ * The class is registered in Guice as a singleton: one instance exists for 
the whole Recon process.
+ * There is no timer, no scheduled task, and no long-lived outbound 
connection. At startup
+ * the constructor only reads configuration and records which providers have 
API keys (for
+ * {@link #isAvailable()} and {@link #getSupportedModels()}). Actual network 
calls happen
+ * only when {@link #chatCompletion} runs on an HTTP request thread.
+ *
+ * Request flow (one chat completion)
+ * Each user message is handled synchronously on the thread that serves the 
REST call:
+ * 
+ * User HTTP request
+ * |
+ * v
+ * Jersey dispatches to ChatbotEndpoint (request thread)
+ * |
+ * v
+ * ChatbotAgent orchestrates tool selection / summarization
+ * |
+ * v
+ * LangChain4jDispatcher.chatCompletion(...)
+ * |
+ * +-- Resolve provider (see below)
+ * |
+ * +-- Build a new ChatLanguageModel for that provider + model name 
(configuration only)
+ * |
+ * +-- Translate ChatMessage list to LangChain4j messages (system / 
user / assistant)
+ * |
+ * +-- chatModel.chat(ChatRequest)  --> outbound HTTPS to the 
vendor (may take seconds)
+ * |
+ * v
+ * LLMResponse returned to the agent, then JSON to the client
+ * 
+ *
+ * How provider routing works
+ * When {@link #chatCompletion} runs, the provider is chosen in this 
order:
+ * 
+ *   Optional {@code _provider} entry in the parameters map (e.g. {@code 
"gemini"}).
+ *   If the model string looks like {@code provider:model}, the prefix 
before {@code :}
+ *   is the provider.
+ *   Otherwise the model name: {@code gpt-} / {@code o1} / {@code o3} → 
{@code openai};
+ *   {@code gemini} → {@code gemini}; {@code claude} → {@code 
anthropic}.
+ *   If still unclear, {@link 
ChatbotConfigKeys#OZONE_RECON_CHATBOT_PROVIDER} is used.
+ * 
+ * For each call, a fresh {@link ChatLanguageModel} is built with the exact 
model id the
+ * caller passed (for example 

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-18 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3263839920


##
pom.xml:
##
@@ -515,6 +569,26 @@
   
 
   
+  
+dev.langchain4j
+langchain4j-anthropic
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-core
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-google-ai-gemini
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-open-ai
+0.36.2
+  

Review Comment:
   Thanks for the suggestion. In principle, using the `langchain4j-bom` is a 
good idea and I agree it would make version updates cleaner. However, Ozone 
manages all dependency versions centrally in the root `pom.xml` under 
``, and every other third-party library in the project 
follows this same pattern of individual version entries. Introducing a BOM 
import for just this one library would be inconsistent with how the rest of the 
project is structured.
   
   Also, worth noting — the `` tags you are seeing are only in the 
root `pom.xml`'s `` block. If you check `recon/pom.xml`, 
the four LangChain4j dependency entries there have no `` tags at all — 
they inherit the version from the root. So there is already a single source of 
truth for the version. Updating it in the future is still just one change in 
the root `pom.xml`. Happy to add the BOM if there is a strong preference, but 
it would require a broader discussion about whether Ozone should standardize 
BOM imports for external libraries.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-17 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3254921803


##
hadoop-ozone/recon/pom.xml:
##
@@ -62,6 +62,22 @@
   commons-io
   commons-io
 
+
+  dev.langchain4j
+  langchain4j-anthropic

Review Comment:
   Thanks for pointing out the OkHttp dependency tree. I dug into this, and 
because `okhttp` (pulled by LangChain4j) and `okhttp-jvm` (pulled by 
OpenTelemetry) have different artifact IDs, Maven doesn't actually treat them 
as a version conflict. This split happened because OkHttp 5.x moved to Kotlin 
Multiplatform and shifted its core classes into the new `-jvm` artifact.
   
   Because they are technically different artifacts, adding an `` 
for `okhttp-jvm` inside the `langchain4j-anthropic` block won't have any 
effect, since LangChain4j doesn't pull in `okhttp-jvm` to begin with (it only 
pulls `okhttp` 4.x).
   
   At runtime, both JARs will be present on the classpath. Fortunately, this 
won't cause a problem because OkHttp 5.x is highly backward-compatible with 
4.x. The JVM will simply load the `OkHttpClient` class from whichever JAR it 
scans first, and both OpenTelemetry and LangChain4j will function normally.
   
   If we ever want to strictly enforce a single OkHttp version across the 
entire project to avoid classpath pollution, the safest way would be to manage 
both `okhttp` and `okhttp-jvm` centrally in the root `hadoop-ozone/pom.xml`'s 
`` section. For the scope of this PR, though, it is safe 
to leave as-is since it won't cause any runtime crashes.



##
hadoop-ozone/recon/pom.xml:
##
@@ -62,6 +62,22 @@
   commons-io
   commons-io
 
+
+  dev.langchain4j
+  langchain4j-anthropic

Review Comment:
   Thanks for pointing out the OkHttp dependency tree. I dug into this, and 
because `okhttp` (pulled by LangChain4j) and `okhttp-jvm` (pulled by 
OpenTelemetry) have different artifact IDs, Maven doesn't actually treat them 
as a version conflict. This split happened because OkHttp 5.x moved to Kotlin 
Multiplatform and shifted its core classes into the new `-jvm` artifact.
   
   Because they are technically different artifacts, adding an `` 
for `okhttp-jvm` inside the `langchain4j-anthropic` block won't have any 
effect, since LangChain4j doesn't pull in `okhttp-jvm` to begin with (it only 
pulls `okhttp` 4.x).
   
   At runtime, both JARs will be present on the classpath. Fortunately, this 
won't cause a problem because OkHttp 5.x is highly backward-compatible with 
4.x. The JVM will simply load the `OkHttpClient` class from whichever JAR it 
scans first, and both OpenTelemetry and LangChain4j will function normally.
   
   If we ever want to strictly enforce a single OkHttp version across the 
entire project to avoid classpath pollution, the safest way would be to manage 
both `okhttp` and `okhttp-jvm` centrally in the root `hadoop-ozone/pom.xml`'s 
`` section. For the scope of this PR, though, it is safe 
to leave as-is since it won't cause any runtime crashes.
   
   cc: @devmadhuu 



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]



Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-12 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3225978467


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,800 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotException;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final String LIST_KEYS_ENDPOINT_SUFFIX = "/keys/listKeys";
+
+  /**
+   * Allowlist of Recon API path prefixes the chatbot is permitted to call.
+   *
+   * This is the primary defence against prompt injection: even if an attacker 
tricks
+   * the LLM into outputting an arbitrary endpoint, the Java layer will reject 
it here
+   * before ToolExecutor makes any network call. Only paths listed here can 
ever be
+   * executed. The check uses prefix matching so that parameterised paths like
+   * /api/v1/containers/unhealthy/MISSING are covered by the 
/api/v1/containers entry.
+   */
+  private static final Set ALLOWED_ENDPOINT_PREFIXES =
+  Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+  "/api/v1/clusterState",
+  "/api/v1/datanodes",
+  "/api/v1/pipelines",
+  "/api/v1/containers",
+  "/api/v1/keys",
+  "/api/v1/volumes",
+  "/api/v1/buckets",
+  "/api/v1/task/status",
+  "/api/v1/metrics",
+  "/api/v1/utilization",
+  "/api/v1/namespace",
+  "/api/v1/om"
+  )));
+
+  // The connection to Gemini/OpenAI
+  private final LLMClient llmClient;
+
+  // The hands that execute the internal API calls
+  private final ToolExecutor toolExecutor;
+
+  // The Cheat Sheet of all available APIs loaded from the .md file
+  private final String apiSchema;
+
+  // Prompt preamble for tool selection — loaded from classpath resource
+  private final String toolSelectionPreamble;
+
+  // System prompt for the summarization LLM call — loaded from classpath 
resource
+  private final String summarizationPrompt;
+
+  // Template for the fallback response when no endpoint matches — loaded from 
classpath resource
+  private final String fallbackPromptTemplate;
+
+  // Max API calls we allow per question (so the LLM doesn't DOS our server)
+  private final int maxToolCalls;
+
+
+  private final String defaultModel;
+  private final int maxRecordsPerAnswer;
+  private final int maxPagesPerAnswer;
+  private final int pageSizePerCall;
+  private final boolean requireSafeScope;
+
+  @Inject
+  public ChatbotAgent(LLMClient llmClient,
+

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-12 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3225921848


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,800 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotException;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final String LIST_KEYS_ENDPOINT_SUFFIX = "/keys/listKeys";
+
+  /**
+   * Allowlist of Recon API path prefixes the chatbot is permitted to call.
+   *
+   * This is the primary defence against prompt injection: even if an attacker 
tricks
+   * the LLM into outputting an arbitrary endpoint, the Java layer will reject 
it here
+   * before ToolExecutor makes any network call. Only paths listed here can 
ever be
+   * executed. The check uses prefix matching so that parameterised paths like
+   * /api/v1/containers/unhealthy/MISSING are covered by the 
/api/v1/containers entry.
+   */
+  private static final Set ALLOWED_ENDPOINT_PREFIXES =
+  Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+  "/api/v1/clusterState",
+  "/api/v1/datanodes",
+  "/api/v1/pipelines",
+  "/api/v1/containers",
+  "/api/v1/keys",
+  "/api/v1/volumes",
+  "/api/v1/buckets",
+  "/api/v1/task/status",
+  "/api/v1/metrics",
+  "/api/v1/utilization",
+  "/api/v1/namespace",
+  "/api/v1/om"
+  )));
+
+  // The connection to Gemini/OpenAI
+  private final LLMClient llmClient;
+
+  // The hands that execute the internal API calls
+  private final ToolExecutor toolExecutor;
+
+  // The Cheat Sheet of all available APIs loaded from the .md file
+  private final String apiSchema;
+
+  // Prompt preamble for tool selection — loaded from classpath resource
+  private final String toolSelectionPreamble;
+
+  // System prompt for the summarization LLM call — loaded from classpath 
resource
+  private final String summarizationPrompt;
+
+  // Template for the fallback response when no endpoint matches — loaded from 
classpath resource
+  private final String fallbackPromptTemplate;
+
+  // Max API calls we allow per question (so the LLM doesn't DOS our server)
+  private final int maxToolCalls;
+
+
+  private final String defaultModel;
+  private final int maxRecordsPerAnswer;
+  private final int maxPagesPerAnswer;
+  private final int pageSizePerCall;
+  private final boolean requireSafeScope;
+
+  @Inject
+  public ChatbotAgent(LLMClient llmClient,
+

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-12 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3225876503


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LLMClient.java:
##
@@ -0,0 +1,185 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * LLMClient is the "Master Contract" for the whole Chatbot system.
+ * 
+ * Purpose:
+ * The ChatbotAgent doesn't know (or care) if it's talking to OpenAI, Gemini, 
or a Local LLM.
+ * It strictly relies on this interface. This interface forces every AI client 
to guarantee
+ * that they will accept exactly the same input and return exactly the same 
output.
+ * 
+ * By using this contract, we can add 10 new AI models to Recon tomorrow,
+ * and we will never have to edit the ChatbotAgent's code to support them!
+ */
+public interface LLMClient {
+
+  /**
+   * The core action: Send a conversation to an AI and wait for its answer.
+   *
+   * API keys are always resolved server-side via
+   * {@link org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper} 
from
+   * the Hadoop credential store or {@code ozone-site.xml}. There is no 
per-request
+   * key parameter — all callers should be cluster admins using the shared 
server key.
+   *
+   * @param messages   The back-and-forth chat history so far (System Prompts, 
User Questions, etc.)
+   * @param model  The specific model name (e.g. "gpt-4.1" or 
"gemini-2.5-flash")
+   * @param parameters Extra rules like "temperature" (how creative the AI 
should be) or
+   *   "max_tokens" (how long the answer can be)
+   * @return A standardized LLMResponse object containing the AI's final text.
+   * @throws LLMException if the network fails, the API key is missing, or the 
provider returns an error.
+   */
+  LLMResponse chatCompletion(
+  List messages,
+  String model,
+  Map parameters) throws LLMException;
+
+  /**
+   * Quick check to see if this client is ready to work (e.g., does it have an 
API key saved?)
+   */
+  boolean isAvailable();
+
+  /**
+   * Asks the AI client for a list of all the different models it supports 
right now.
+   * We use this to populate the drop-down menu in the user interface!
+   */
+  List getSupportedModels();
+
+  // =
+  // Data Transfer Objects (DTOs)
+  // These are the standardized containers we use to pass information around.
+  // =
+
+  /**
+   * A single message in a conversation.
+   * Every message needs a "role" (who is speaking: user or assistant) 
+   * and "content" (what they actually said).
+   */
+  class ChatMessage {
+private final String role;
+private final String content;
+
+public ChatMessage(String role, String content) {
+  this.role = role;
+  this.content = content;
+}
+
+public String getRole() {
+  return role;
+}
+
+public String getContent() {
+  return content;
+}
+  }
+
+  /**
+   * The standardized package that every AI MUST return when it finishes 
thinking.
+   * Instead of OpenAI returning one JSON format and Gemini returning a 
completely different one,
+   * our background code forces them both to output this clean Java object.
+   */
+  class LLMResponse {
+
+// The actual text the AI typed out
+private final String content;
+
+// Which AI model specifically answered this? (e.g. "gpt-4")
+private final String model;
+
+// How many "words" the user asked
+private final int promptTokens;
+
+// How many "words" the AI answered with
+private final int completionTokens;
+
+// Extra sneaky information about the answer (like why it stopped typing)
+private final Map metadata;
+
+public LLMResponse(String content, String model,
+   int promptTokens, int completionTokens,
+   Map metadata) {
+  this.content = content;
+  this.model = model;
+  this.promptTokens = promptTokens;
+  this.completi

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-12 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3225839755


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/ReconRestServletModule.java:
##
@@ -65,7 +67,7 @@ public ReconRestServletModule(ConfigurationSource conf) {
 
   @Override
   protected void configureServlets() {
-configureApi(BASE_API_PATH, API_PACKAGE);
+configureApi(BASE_API_PATH, API_PACKAGE, CHATBOT_API_PACKAGE);

Review Comment:
   Always gets registered regardless of feature flag.



##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,800 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotException;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final Pattern JSON_PATTERN = Pattern.compile("\\{.*\\}", 
Pattern.DOTALL);
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final String LIST_KEYS_ENDPOINT_SUFFIX = "/keys/listKeys";
+
+  /**
+   * Allowlist of Recon API path prefixes the chatbot is permitted to call.
+   *
+   * This is the primary defence against prompt injection: even if an attacker 
tricks
+   * the LLM into outputting an arbitrary endpoint, the Java layer will reject 
it here
+   * before ToolExecutor makes any network call. Only paths listed here can 
ever be
+   * executed. The check uses prefix matching so that parameterised paths like
+   * /api/v1/containers/unhealthy/MISSING are covered by the 
/api/v1/containers entry.
+   */
+  private static final Set ALLOWED_ENDPOINT_PREFIXES =
+  Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
+  "/api/v1/clusterState",
+  "/api/v1/datanodes",
+  "/api/v1/pipelines",
+  "/api/v1/containers",
+  "/api/v1/keys",
+  "/api/v1/volumes",
+  "/api/v1/buckets",
+  "/api/v1/task/status",
+  "/api/v1/metrics",
+  "/api/v1/utilization",
+  "/api/v1/namespace",
+  "/api/v1/om"
+  )));
+
+  // The connection to Gemini/OpenAI
+  private final LLMClient llmClient;
+
+  // The hands that execute the internal API calls
+  private final ToolExecutor toolExecutor;
+
+  // The Cheat Sheet of all available APIs loaded from the .md file
+  private final String apiSchema;
+
+  // Prompt preamble for tool selection — loaded from classpath resource
+  private final String toolSelectionPreamble;
+
+  // System prompt for the summarization LLM call — loaded from classpath 
resource
+  private final String summarizationPrompt;
+
+  // Template for the fallback response when no endpoint matches — loaded from 
classpath resource
+  priva

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-12 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3224534208


##
hadoop-ozone/recon/pom.xml:
##
@@ -62,6 +62,22 @@
   commons-io
   commons-io
 
+
+  dev.langchain4j
+  langchain4j-anthropic

Review Comment:
   If you run `mvn dependency:tree` this dependency of `okhttp:4.12.0` will be 
emitted as a transitive dependency at compile time from this artifact: 
`langchain4j-anthropic` and same `okhttp-jvm:5.3.2` of different version will 
be emitted at runtime from `opentelemetry-exporter-sender-okhttp` artifact from 
main pom.xml. So adding an exclusion for `okhttp-jvm` in the recon pom.xml 
should be done.



##
pom.xml:
##
@@ -515,6 +569,26 @@
   
 
   
+  
+dev.langchain4j
+langchain4j-anthropic
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-core
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-google-ai-gemini
+0.36.2
+  
+  
+dev.langchain4j
+langchain4j-open-ai
+0.36.2
+  

Review Comment:
   each langchain4j-* artifact added separately at 0.36.2 version rather than 
importing the langchain4j-bom. If need update of version later for 4 separate 
version entries, we should use bom



##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/LangChain4jDispatcher.java:
##
@@ -0,0 +1,405 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import dev.langchain4j.data.message.AiMessage;
+import dev.langchain4j.data.message.SystemMessage;
+import dev.langchain4j.data.message.UserMessage;
+import dev.langchain4j.model.anthropic.AnthropicChatModel;
+import dev.langchain4j.model.chat.ChatLanguageModel;
+import dev.langchain4j.model.chat.request.ChatRequest;
+import dev.langchain4j.model.chat.response.ChatResponse;
+import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel;
+import dev.langchain4j.model.openai.OpenAiChatModel;
+import dev.langchain4j.model.output.TokenUsage;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.time.Duration;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@link LLMClient} implementation that sends chat requests to cloud LLM 
providers using
+ * https://github.com/langchain4j/langchain4j";>LangChain4j.
+ *
+ * Purpose
+ * The Recon chatbot needs to call external APIs (OpenAI, Google Gemini, 
Anthropic Claude)
+ * with a stable Java contract. This class is the only place that talks to 
LangChain4j: it
+ * picks the right provider, builds a {@link ChatLanguageModel} for the 
requested model,
+ * converts messages into LangChain4j types, runs one completion, and maps the 
result back to
+ * {@link LLMResponse}. Higher layers ({@link 
org.apache.hadoop.ozone.recon.chatbot.agent.ChatbotAgent},
+ * {@link org.apache.hadoop.ozone.recon.chatbot.api.ChatbotEndpoint}) depend 
only on {@link LLMClient}.
+ *
+ * Lifecycle (no background work)
+ * The class is registered in Guice as a singleton: one instance exists for 
the whole Recon process.
+ * There is no timer, no scheduled task, and no long-lived outbound 
connection. At startup
+ * the constructor only reads configuration and records which providers have 
API keys (for
+ * {@link #isAvailable()} and {@link #getSupportedModels()}). Actual network 
calls happen
+ * only when {@link #chatCompletion} runs on an HTTP request thread.
+ *
+ * Request flow (one chat completion)
+ * Each user message is handled synchronously on the thread that serves the 
REST call:
+ * 
+ * User HTTP request
+ * |
+ * v
+ * Jersey dispatches to ChatbotEndpoint (request thread)
+ * |
+ * v
+ * ChatbotAgent orchestrates tool selection / summarization
+ * |
+ * v
+ * LangC

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-11 Thread via GitHub


ArafatKhan2198 commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3221115668


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/api/ChatbotEndpoint.java:
##
@@ -0,0 +1,268 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.api;
+
+import javax.inject.Inject;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.agent.ChatbotAgent;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * REST API endpoint for the Recon Chatbot.
+ *
+ * 
+ * API keys are managed via JCEKS (admin-configured),
+ * so there are no per-user key storage endpoints.
+ * 
+ */
+@Path("/chatbot")
+@Produces(MediaType.APPLICATION_JSON)
+public class ChatbotEndpoint {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotEndpoint.class);
+
+  private final ChatbotAgent chatbotAgent;
+  private final LLMClient llmClient;
+  private final OzoneConfiguration configuration;
+
+  @Inject
+  public ChatbotEndpoint(ChatbotAgent chatbotAgent,
+  LLMClient llmClient,
+  OzoneConfiguration configuration) {
+this.chatbotAgent = chatbotAgent;
+this.llmClient = llmClient;
+this.configuration = configuration;
+
+LOG.info("ChatbotEndpoint initialized via Guice injection");
+  }
+
+  /**
+   * Checks if the chatbot is enabled in configuration.
+   */
+  private boolean isChatbotEnabled() {
+return configuration.getBoolean(
+ChatbotConfigKeys.OZONE_RECON_CHATBOT_ENABLED,
+ChatbotConfigKeys.OZONE_RECON_CHATBOT_ENABLED_DEFAULT);
+  }
+
+  /**
+   * Health check endpoint.
+   */
+  @GET
+  @Path("/health")
+  public Response health() {
+Map response = new HashMap<>();
+boolean enabled = isChatbotEnabled();
+response.put("enabled", enabled);
+response.put("llmClientAvailable",
+enabled && llmClient != null && llmClient.isAvailable());
+return Response.ok(response).build();
+  }
+
+  /**
+   * Chat endpoint - processes a user query.
+   */
+  @POST
+  @Path("/chat")
+  @Consumes(MediaType.APPLICATION_JSON)
+  public Response chat(ChatRequest request) {
+
+// Safety check 1: If chatbot is disabled, throw a 503 Service Unavailable 
error immediately.
+if (!isChatbotEnabled()) {
+  return Response.status(Response.Status.SERVICE_UNAVAILABLE)
+  .entity(Collections.singletonMap("error", "Chatbot service is not 
enabled"))
+  .build();
+}
+
+// Safety check 2: If the user didn't really ask a question, throw a 400 
Bad Request.
+if (request.getQuery() == null || request.getQuery().trim().isEmpty()) {
+  return Response.status(Response.Status.BAD_REQUEST)
+  .entity(Collections.singletonMap("error", "Query cannot be empty"))
+  .build();
+}
+
+try {
+  LOG.info("Chat request: userId={}, model={}, provider={}",
+  sanitizeUserId(request.getUserId()),
+  request.getModel() == null ? "default" : request.getModel(),
+  request.getProvider() == null ? "auto" : request.getProvider());
+
+  // Pass the user's question to the Brain (ChatbotAgent) to do all the 
hard work.
+  // This step takes a few seconds because it talks to Gemini and the 
Recon APIs.
+  String response = chatbotAgent.processQuery(
+  request.getQuery(),
+  request.getModel(),
+  request.getProvider(),
+  null);

Review Comment:
   As discussed earlier in our discussions, Recon currently has no per-user 
authorization model all authenticated users are cluster admins with identical 
access. The server-side shared API key is consistent with how all other Recon 
credentials work. Per-user key management w

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-11 Thread via GitHub


devmadhuu commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3218443087


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/llm/AnthropicClient.java:
##
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.llm;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.security.CredentialHelper;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Direct client for Anthropic Claude models using Composition.
+ */
+public class AnthropicClient implements LLMClient {
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+  private static final String ANTHROPIC_VERSION = "2023-06-01";
+
+  private final OzoneConfiguration configuration;
+  private final CredentialHelper credentialHelper;
+  private final LLMNetworkClient networkClient;
+
+  public AnthropicClient(OzoneConfiguration configuration,
+ CredentialHelper credentialHelper,
+ int timeoutMs) {
+this.configuration = configuration;
+this.credentialHelper = credentialHelper;
+this.networkClient = new LLMNetworkClient(timeoutMs);
+  }
+
+  @Override
+  public LLMResponse chatCompletion(List messages, String model, 
String apiKey, Map parameters) throws LLMException {

Review Comment:
   Do we not need to whitelists body parameters via `ALLOWED_BODY_PARAMS` here 
also same as `OpenAIClient` ?



##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/agent/ChatbotAgent.java:
##
@@ -0,0 +1,809 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.agent;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.inject.Inject;
+import com.google.inject.Singleton;
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ozone.recon.chatbot.ChatbotConfigKeys;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.ChatMessage;
+import org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient.LLMResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Main chatbot agent that orchestrates the conversation flow.
+ * Handles tool selection (figuring out what API to call), executing those 
calls,
+ * and summarization (feeding the data back to the LLM to write a nice answer).
+ */
+@Singleton
+public class ChatbotAgent {
+
+  private static final Logger LOG = 
LoggerFactory.getLogger(ChatbotAgent.class);
+
+  private static final ObjectMapper MAPPER = new ObjectMapper();
+
+  // A specific Recon API endpoint we want to handle carefully because it can 
return millions of rows.
+  private static final Strin

Re: [PR] HDDS-14816. Add Recon AI Assistant backend foundation with Multi LLM integration [ozone]

2026-05-08 Thread via GitHub


priyeshkaratha commented on code in PR #9915:
URL: https://github.com/apache/ozone/pull/9915#discussion_r3210195726


##
hadoop-ozone/recon/src/main/java/org/apache/hadoop/ozone/recon/chatbot/security/LLMClient2.java:
##
@@ -0,0 +1,182 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.ozone.recon.chatbot.security;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * LLMClient is the "Master Contract" for the whole Chatbot system.
+ * 
+ * Purpose:
+ * The ChatbotAgent doesn't know (or care) if it's talking to OpenAI, Gemini, 
or a Local LLM.
+ * It strictly relies on this interface. This interface forces every AI client 
to guarantee
+ * that they will accept exactly the same input and return exactly the same 
output.
+ * 
+ * By using this contract, we can add 10 new AI models to Recon tomorrow,
+ * and we will never have to edit the ChatbotAgent's code to support them!
+ */
+public interface LLMClient2 {

Review Comment:
   This file seems like duplicate of 
org.apache.hadoop.ozone.recon.chatbot.llm.LLMClient



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


-
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]