From 7c73cd244cc4345fb66fb2fa169d6cf6896f3108 Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Fri, 6 Feb 2026 15:33:32 -0800 Subject: [PATCH 1/3] Work around some race conditions in MCP prototype --- .../org/labkey/core/mpc/McpServiceImpl.java | 80 +++++++++++++------ .../org/labkey/query/controllers/LabKeySql.md | 41 +++++++--- 2 files changed, 85 insertions(+), 36 deletions(-) diff --git a/core/src/org/labkey/core/mpc/McpServiceImpl.java b/core/src/org/labkey/core/mpc/McpServiceImpl.java index 6aa6f9d7d56..8e121ccd6e9 100644 --- a/core/src/org/labkey/core/mpc/McpServiceImpl.java +++ b/core/src/org/labkey/core/mpc/McpServiceImpl.java @@ -65,7 +65,9 @@ import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; +import java.util.ConcurrentModificationException; import java.util.List; +import java.util.NoSuchElementException; import java.util.Objects; import java.util.function.Supplier; @@ -335,23 +337,33 @@ public ChatClient getChat(HttpSession session, String agentName, Supplier sendMessageEx(ChatClient chatSession, String messag { if (isBlank(message)) return List.of(); - var callResponse = chatSession - .prompt(message) - .toolContext(McpContext.get().getToolContext().getContext()) - .call(); - List ret = new ArrayList<>(); - for (Generation result : callResponse.chatResponse().getResults()) + try { - var output = result.getOutput(); - if (ASSISTANT == output.getMessageType()) + var callResponse = chatSession + .prompt(message) + .toolContext(McpContext.get().getToolContext().getContext()) + .call(); + List ret = new ArrayList<>(); + for (Generation result : callResponse.chatResponse().getResults()) { - String md = output.getText(); - HtmlString html = HtmlString.unsafe(MarkdownService.get().toHtml(md)); - ret.add(new MessageResponse("text/markdown", md, html)); + var output = result.getOutput(); + if (ASSISTANT == output.getMessageType()) + { + String md = output.getText(); + HtmlString html = HtmlString.unsafe(MarkdownService.get().toHtml(md)); + ret.add(new MessageResponse("text/markdown", md, html)); + } } + return ret; + } + catch (NoSuchElementException x) + { + // Spring AI GoogleGenAiChatModel bug: empty candidates cause NoSuchElementException + // https://github.com/spring-projects/spring-ai/issues/4556 + LOG.warn("Empty response from chat model (likely a filtered or empty candidate)", x); + return List.of(new MessageResponse("text/plain", "The model returned an empty response. Please try rephrasing your question.", HtmlString.of("The model returned an empty response. Please try rephrasing your question."))); + } + catch (ConcurrentModificationException x) + { + // This can happen when the vector store is still loading, typically a problem shortly after startup + // Should do better synchronization or state checking + LOG.warn("Vector store not ready", x); + return List.of(new MessageResponse("text/plain", "Vector store likely not ready yet. Try again.", HtmlString.of("Vector store likely not ready yet. Try again."))); } - return ret; } @@ -464,6 +493,7 @@ public String getModel() // gemini-2.5-flash // gemini-2.5-pro // gemini-3-flash-preview + // gemini-3-pro-preview } @Override diff --git a/query/src/org/labkey/query/controllers/LabKeySql.md b/query/src/org/labkey/query/controllers/LabKeySql.md index 9beef68e462..82f4e45ca78 100644 --- a/query/src/org/labkey/query/controllers/LabKeySql.md +++ b/query/src/org/labkey/query/controllers/LabKeySql.md @@ -57,16 +57,16 @@ A `PIVOT` query helps you summarize and re-visualize data by transforming rows i PIVOT new_column_name BY pivoting_column IN ('value1', 'value2') ``` Note that pivot column names are case-sensitive. You may need to use `LOWER()` or `UPPER()` in your query to work around this issue. -* **Pivoting by Two Columns:** - Two levels of `PIVOT` are not directly supported. However, you can achieve a similar result by concatenating the two values together and pivoting on that "calculated" column. - ```sql - SELECT - Run.SampleCondition || ' ' || PeakLabel AS ConditionPeak, - AVG(Data.PercTimeCorrArea) AS AvgPercTimeCorrArea - FROM Data - GROUP BY Run.SampleCondition || ' ' || PeakLabel - PIVOT AvgPercTimeCorrArea BY ConditionPeak - ``` + * **Pivoting by Two Columns:** + Two levels of `PIVOT` are not directly supported. However, you can achieve a similar result by concatenating the two values together and pivoting on that "calculated" column. + ```sql + SELECT + Run.SampleCondition || ' ' || PeakLabel AS ConditionPeak, + AVG(Data.PercTimeCorrArea) AS AvgPercTimeCorrArea + FROM Data + GROUP BY Run.SampleCondition || ' ' || PeakLabel + PIVOT AvgPercTimeCorrArea BY ConditionPeak + ``` ----- @@ -130,7 +130,26 @@ LabKey SQL allows you to directly annotate your SQL statements to override how c ----- -### **7. Available Methods** +### **7. Container Filters** + +In addition to targeting a container by its path, LabKey SQL supports container filters to alter the scope +of a query. Annotate tables in the FROM clause with an optional container filter. Syntax: + +SELECT * FROM Issues [ContainerFilter='CurrentAndSubfolders'] alias + +Possible values include: +- AllFolders +- AllInProject +- AllInProjectPlusShared +- Current +- CurrentAndFirstChildren +- CurrentAndParents +- CurrentAndSubfolders +- CurrentAndSubfoldersPlusShared +- CurrentPlusProject +- CurrentPlusProjectAndShared. + +### **8. Available Methods** Here is a summary of the available functions and methods in LabKey SQL. From c08bda9e9ad11438880c894846f8d1556e22aa5d Mon Sep 17 00:00:00 2001 From: labkey-jeckels Date: Fri, 6 Feb 2026 16:58:36 -0800 Subject: [PATCH 2/3] Alternate wording --- core/src/org/labkey/core/mpc/McpServiceImpl.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/src/org/labkey/core/mpc/McpServiceImpl.java b/core/src/org/labkey/core/mpc/McpServiceImpl.java index 8e121ccd6e9..2b2d6b40884 100644 --- a/core/src/org/labkey/core/mpc/McpServiceImpl.java +++ b/core/src/org/labkey/core/mpc/McpServiceImpl.java @@ -316,6 +316,11 @@ public ChatClient getChat(HttpSession session, String agentName, Supplier Date: Fri, 6 Feb 2026 16:59:16 -0800 Subject: [PATCH 3/3] Revert accidental commit --- core/src/org/labkey/core/mpc/McpServiceImpl.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/core/src/org/labkey/core/mpc/McpServiceImpl.java b/core/src/org/labkey/core/mpc/McpServiceImpl.java index 2b2d6b40884..422d0140223 100644 --- a/core/src/org/labkey/core/mpc/McpServiceImpl.java +++ b/core/src/org/labkey/core/mpc/McpServiceImpl.java @@ -317,10 +317,6 @@ public ChatClient getChat(HttpSession session, String agentName, Supplier