mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-30 18:13:23 +08:00
Merge pull request #22707 from dannon/rebrand-chatgxy
Rebrand ChatGXY to GalaxyAI
This commit is contained in:
@@ -16,7 +16,7 @@ import { useUnprivilegedToolStore } from "@/stores/unprivilegedToolStore";
|
||||
import { useUserStore } from "@/stores/userStore";
|
||||
import localize from "@/utils/localization";
|
||||
|
||||
import ChatHistoryPanel from "../ChatGXY/ChatHistoryPanel.vue";
|
||||
import ChatHistoryPanel from "../GalaxyAI/ChatHistoryPanel.vue";
|
||||
import InvocationsPanel from "../Panels/InvocationsPanel.vue";
|
||||
import ActivityBarHeader from "./ActivityBarHeader.vue";
|
||||
import ActivityBarSeparator from "./ActivityBarSeparator.vue";
|
||||
@@ -127,7 +127,7 @@ const activities = computed({
|
||||
if (activity.id === "interactivetools" && !config.value?.interactivetools_enable) {
|
||||
return false;
|
||||
}
|
||||
if (activity.id === "chatgxy" && !config.value?.llm_api_configured) {
|
||||
if (activity.id === "galaxyai" && !config.value?.llm_api_configured) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -139,7 +139,7 @@ const activities = computed({
|
||||
(activity) =>
|
||||
(activity.id === "user-defined-tools" && !canUseUnprivilegedTools.value) ||
|
||||
(activity.id === "interactivetools" && !config.value?.interactivetools_enable) ||
|
||||
(activity.id === "chatgxy" && !config.value?.llm_api_configured),
|
||||
(activity.id === "galaxyai" && !config.value?.llm_api_configured),
|
||||
);
|
||||
storeActivities.value = [...newActivities, ...filteredOut];
|
||||
},
|
||||
@@ -425,7 +425,7 @@ defineExpose({
|
||||
<InvocationsPanel v-else-if="isActiveSideBar('invocation')" />
|
||||
<VisualizationPanel v-else-if="isActiveSideBar('visualizations')" />
|
||||
<MultiviewPanel v-else-if="isActiveSideBar('multiview')" />
|
||||
<ChatHistoryPanel v-else-if="isActiveSideBar('chatgxy')" />
|
||||
<ChatHistoryPanel v-else-if="isActiveSideBar('galaxyai')" />
|
||||
<NotificationsPanel v-else-if="isActiveSideBar('notifications')" />
|
||||
<UserToolPanel v-if="isActiveSideBar('user-defined-tools')" in-panel />
|
||||
<InteractiveToolsPanel v-else-if="isActiveSideBar('interactivetools')" />
|
||||
|
||||
@@ -10,12 +10,12 @@ import { type AgentResponse, useAgentActions } from "@/composables/agentActions"
|
||||
import { useMarkdown } from "@/composables/markdown";
|
||||
import { errorMessageAsString } from "@/utils/simple-error";
|
||||
|
||||
import { getAgentIcon } from "./ChatGXY/agentTypes";
|
||||
import type { ChatHistoryItem, ChatMessage } from "./ChatGXY/chatTypes";
|
||||
import { generateId, scrollToBottom } from "./ChatGXY/chatUtils";
|
||||
import { getAgentIcon } from "./GalaxyAI/agentTypes";
|
||||
import type { ChatHistoryItem, ChatMessage } from "./GalaxyAI/chatTypes";
|
||||
import { generateId, scrollToBottom } from "./GalaxyAI/chatUtils";
|
||||
|
||||
import ChatInput from "./ChatGXY/ChatInput.vue";
|
||||
import ChatMessageCell from "./ChatGXY/ChatMessageCell.vue";
|
||||
import ChatInput from "./GalaxyAI/ChatInput.vue";
|
||||
import ChatMessageCell from "./GalaxyAI/ChatMessageCell.vue";
|
||||
import Heading from "@/components/Common/Heading.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
@@ -71,7 +71,7 @@ function showWelcome() {
|
||||
id: generateId(),
|
||||
role: "assistant",
|
||||
content:
|
||||
"Welcome to ChatGXY. Ask about tools, workflows, errors, or data quality " +
|
||||
"Welcome to GalaxyAI. Ask about tools, workflows, errors, or data quality " +
|
||||
"and your question will be routed to the appropriate specialist agent.",
|
||||
timestamp: new Date(),
|
||||
agentType: "router",
|
||||
@@ -118,7 +118,7 @@ async function submitQuery() {
|
||||
});
|
||||
|
||||
if (error) {
|
||||
const errorText = errorMessageAsString(error, "Failed to get response from ChatGXY.");
|
||||
const errorText = errorMessageAsString(error, "Failed to get response from GalaxyAI.");
|
||||
const errorMsg: ChatMessage = {
|
||||
id: generateId(),
|
||||
role: "assistant",
|
||||
@@ -322,17 +322,17 @@ async function deleteCurrentChat() {
|
||||
|
||||
function popOutToWindowManager() {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
const path = currentChatId.value ? `/chatgxy/${currentChatId.value}` : "/chatgxy";
|
||||
const path = currentChatId.value ? `/galaxyai/${currentChatId.value}` : "/galaxyai";
|
||||
const url = `${path}?compact=true`;
|
||||
Galaxy.frame.add({ title: "ChatGXY", url });
|
||||
Galaxy.frame.add({ title: "GalaxyAI", url });
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="chatgxy-container" :class="{ 'chatgxy-compact': compact }">
|
||||
<div v-if="!compact" class="chatgxy-header">
|
||||
<div class="galaxyai-container" :class="{ 'galaxyai-compact': compact }">
|
||||
<div v-if="!compact" class="galaxyai-header">
|
||||
<Heading h2 :icon="faMagic" size="lg">
|
||||
<span>ChatGXY</span>
|
||||
<span>GalaxyAI</span>
|
||||
</Heading>
|
||||
<div class="header-actions">
|
||||
<button class="btn btn-sm btn-outline-primary" title="Start New Chat" @click="startNewChat">
|
||||
@@ -380,7 +380,7 @@ function popOutToWindowManager() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="chatgxy-footer">
|
||||
<div class="galaxyai-footer">
|
||||
<ChatInput v-model="query" :busy="busy" @submit="submitQuery" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -389,7 +389,7 @@ function popOutToWindowManager() {
|
||||
<style lang="scss" scoped>
|
||||
@import "@/style/scss/theme/blue.scss";
|
||||
|
||||
.chatgxy-container {
|
||||
.galaxyai-container {
|
||||
height: calc(100vh - #{$masthead-height} - 2rem);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -398,19 +398,19 @@ function popOutToWindowManager() {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.chatgxy-compact {
|
||||
.galaxyai-compact {
|
||||
height: 100vh;
|
||||
|
||||
.chat-messages {
|
||||
padding: 0.75rem 1rem;
|
||||
}
|
||||
|
||||
.chatgxy-footer {
|
||||
.galaxyai-footer {
|
||||
padding: 0.5rem 0.75rem;
|
||||
}
|
||||
}
|
||||
|
||||
.chatgxy-header {
|
||||
.galaxyai-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
@@ -424,7 +424,7 @@ function popOutToWindowManager() {
|
||||
}
|
||||
}
|
||||
|
||||
.chatgxy-footer {
|
||||
.galaxyai-footer {
|
||||
padding: 0.75rem 1rem;
|
||||
background: $panel-bg-color;
|
||||
border-top: $border-default;
|
||||
+5
-5
@@ -58,9 +58,9 @@ function handleItemClick(item: ChatHistoryItem, index: number, event: MouseEvent
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (Galaxy?.frame?.active) {
|
||||
// @ts-ignore - monkeypatched router, second arg is RouterPushOptions
|
||||
router.push(`/chatgxy/${item.id}?compact=true`, { title: "ChatGXY" });
|
||||
router.push(`/galaxyai/${item.id}?compact=true`, { title: "GalaxyAI" });
|
||||
} else {
|
||||
router.push(`/chatgxy/${item.id}`);
|
||||
router.push(`/galaxyai/${item.id}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,9 +68,9 @@ function startNewChat() {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (Galaxy?.frame?.active) {
|
||||
// @ts-ignore - monkeypatched router, second arg is RouterPushOptions
|
||||
router.push("/chatgxy?compact=true", { title: "ChatGXY" });
|
||||
router.push("/galaxyai?compact=true", { title: "GalaxyAI" });
|
||||
} else {
|
||||
router.push("/chatgxy");
|
||||
router.push("/galaxyai");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ async function deleteSelected() {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<ActivityPanel title="ChatGXY" go-to-all-title="Open ChatGXY" href="/chatgxy">
|
||||
<ActivityPanel title="GalaxyAI" go-to-all-title="Open GalaxyAI" href="/galaxyai">
|
||||
<template v-slot:header-buttons>
|
||||
<button class="btn btn-sm btn-outline-primary" title="New Chat" @click="startNewChat">
|
||||
<FontAwesomeIcon :icon="faPlus" fixed-width />
|
||||
@@ -8,8 +8,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { usePageEditorStore } from "@/stores/pageEditorStore";
|
||||
|
||||
import PageChatPanel from "./PageChatPanel.vue";
|
||||
import ChatInput from "@/components/ChatGXY/ChatInput.vue";
|
||||
import ChatMessageCell from "@/components/ChatGXY/ChatMessageCell.vue";
|
||||
import ChatInput from "@/components/GalaxyAI/ChatInput.vue";
|
||||
import ChatMessageCell from "@/components/GalaxyAI/ChatMessageCell.vue";
|
||||
|
||||
// Mock GalaxyApi
|
||||
const mockPOST = vi.fn();
|
||||
|
||||
@@ -10,8 +10,8 @@ import { BAlert, BButton, BSkeleton } from "bootstrap-vue";
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
|
||||
import { GalaxyApi } from "@/api";
|
||||
import type { ChatMessage } from "@/components/ChatGXY/chatTypes";
|
||||
import { generateId, scrollToBottom } from "@/components/ChatGXY/chatUtils";
|
||||
import type { ChatMessage } from "@/components/GalaxyAI/chatTypes";
|
||||
import { generateId, scrollToBottom } from "@/components/GalaxyAI/chatUtils";
|
||||
import { PAGE_LABELS } from "@/components/Page/constants";
|
||||
import { type AgentResponse, type EditProposal, useAgentActions } from "@/composables/agentActions";
|
||||
import { useMarkdown } from "@/composables/markdown";
|
||||
@@ -23,8 +23,8 @@ import { applySectionEdit } from "./sectionDiffUtils";
|
||||
import PageChatHistoryList from "./PageChatHistoryList.vue";
|
||||
import ProposalDiffView from "./ProposalDiffView.vue";
|
||||
import SectionPatchView from "./SectionPatchView.vue";
|
||||
import ChatInput from "@/components/ChatGXY/ChatInput.vue";
|
||||
import ChatMessageCell from "@/components/ChatGXY/ChatMessageCell.vue";
|
||||
import ChatInput from "@/components/GalaxyAI/ChatInput.vue";
|
||||
import ChatMessageCell from "@/components/GalaxyAI/ChatMessageCell.vue";
|
||||
import LoadingSpan from "@/components/LoadingSpan.vue";
|
||||
|
||||
const props = withDefaults(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* Composable for fetching and watching history datasets based on filter criteria.
|
||||
* This encapsulates the logic for fetching datasets when history ID, update time,
|
||||
* or filter text changes, making it reusable across components like `CollectionCreatorIndex`
|
||||
* (and in the future `ChatGXY`).
|
||||
* (and in the future `GalaxyAI`).
|
||||
*/
|
||||
import { type MaybeRefOrGetter, toValue } from "@vueuse/shared";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
||||
@@ -18,7 +18,6 @@ import { patchRouterPush } from "./router-push";
|
||||
import CenterFrame from "./modules/CenterFrame.vue";
|
||||
import AboutGalaxy from "@/components/AboutGalaxy.vue";
|
||||
import AvailableDatatypes from "@/components/AvailableDatatypes/AvailableDatatypes.vue";
|
||||
import ChatGXY from "@/components/ChatGXY.vue";
|
||||
import CitationsList from "@/components/Citation/CitationsList.vue";
|
||||
import ClientError from "@/components/ClientError.vue";
|
||||
import CollectionEditView from "@/components/Collections/common/CollectionEditView.vue";
|
||||
@@ -36,6 +35,7 @@ import ManageFileSourceIndex from "@/components/FileSources/Instances/ManageInde
|
||||
import UpgradeFileSourceInstance from "@/components/FileSources/Instances/UpgradeInstance.vue";
|
||||
import CreateUserFileSource from "@/components/FileSources/Templates/CreateUserFileSource.vue";
|
||||
import FormGeneric from "@/components/Form/FormGeneric.vue";
|
||||
import GalaxyAI from "@/components/GalaxyAI.vue";
|
||||
import GalaxyWizard from "@/components/GalaxyWizard.vue";
|
||||
import GridInvocation from "@/components/Grid/GridInvocation.vue";
|
||||
import GridPage from "@/components/Grid/GridPage.vue";
|
||||
@@ -618,8 +618,8 @@ export function getRouter(Galaxy) {
|
||||
component: TourList,
|
||||
},
|
||||
{
|
||||
path: "chatgxy/:exchangeId?",
|
||||
component: ChatGXY,
|
||||
path: "galaxyai/:exchangeId?",
|
||||
component: GalaxyAI,
|
||||
redirect: redirectAnon(),
|
||||
props: (route) => ({
|
||||
exchangeId: route.params.exchangeId || undefined,
|
||||
|
||||
@@ -68,15 +68,15 @@ export const defaultActivities = [
|
||||
anonymous: false,
|
||||
description: "AI-powered assistant to help with Galaxy tasks and troubleshooting.",
|
||||
icon: faComments,
|
||||
id: "chatgxy",
|
||||
id: "galaxyai",
|
||||
mutable: false,
|
||||
optional: true,
|
||||
panel: true,
|
||||
title: "ChatGXY",
|
||||
to: "/chatgxy",
|
||||
tooltip: "Chat with Galaxy AI Assistant",
|
||||
title: "GalaxyAI",
|
||||
to: "/galaxyai",
|
||||
tooltip: "Chat with GalaxyAI",
|
||||
visible: true,
|
||||
windowTitle: "ChatGXY",
|
||||
windowTitle: "GalaxyAI",
|
||||
},
|
||||
{
|
||||
anonymous: true,
|
||||
|
||||
@@ -1636,13 +1636,13 @@ job_details:
|
||||
selector: '//td[@id="galaxy-tool-id"][normalize-space(text()) = "${tool_id}"]'
|
||||
tool_exit_code: '#exit-code'
|
||||
|
||||
chatgxy:
|
||||
galaxyai:
|
||||
selectors:
|
||||
activity: '#activity-chatgxy'
|
||||
_: '.chatgxy-container'
|
||||
header: '.chatgxy-header'
|
||||
new_chat_button: '.chatgxy-header .btn-outline-primary'
|
||||
delete_chat_button: '.chatgxy-header .btn-outline-danger'
|
||||
activity: '#activity-galaxyai'
|
||||
_: '.galaxyai-container'
|
||||
header: '.galaxyai-header'
|
||||
new_chat_button: '.galaxyai-header .btn-outline-primary'
|
||||
delete_chat_button: '.galaxyai-header .btn-outline-danger'
|
||||
messages: '.chat-messages'
|
||||
input: '#chat-input'
|
||||
send_button: '.send-button'
|
||||
@@ -1659,7 +1659,7 @@ chatgxy:
|
||||
|
||||
history_panel:
|
||||
selectors:
|
||||
_: '.activity-panel[data-description="ChatGXY"]'
|
||||
_: '.activity-panel[data-description="GalaxyAI"]'
|
||||
toggle_selection_mode: 'button[title="Select chats to delete"]'
|
||||
cancel_selection: 'button[title="Cancel selection"]'
|
||||
history_item: '[data-description="sidebar item"]'
|
||||
|
||||
@@ -6,14 +6,14 @@ Galaxy includes a multi-agent AI system built on [pydantic-ai](https://github.co
|
||||
|
||||
When AI is configured, Galaxy exposes two main user-facing features:
|
||||
|
||||
- **ChatGXY**: A sidebar chat interface (visible in the Activity Bar) that routes user questions to specialized agents.
|
||||
- **GalaxyAI**: A sidebar chat interface (visible in the Activity Bar) that routes user questions to specialized agents.
|
||||
- **GalaxyWizard**: An error-analysis widget that appears on failed job pages to help users understand what went wrong.
|
||||
|
||||
All AI configuration lives in `galaxy.yml` under the `galaxy:` section. There is no admin UI for toggling agents -- everything is controlled through configuration files.
|
||||
|
||||
## Minimum Required Configuration
|
||||
|
||||
The recommended way to configure AI is through `inference_services`. Setting this value (or the deprecated `ai_api_key` / `ai_api_base_url`) is what activates the entire agent system. Without at least one of these, no agent code loads, the ChatGXY sidebar entry is hidden, and the GalaxyWizard error-analysis widget does not appear.
|
||||
The recommended way to configure AI is through `inference_services`. Setting this value (or the deprecated `ai_api_key` / `ai_api_base_url`) is what activates the entire agent system. Without at least one of these, no agent code loads, the GalaxyAI sidebar entry is hidden, and the GalaxyWizard error-analysis widget does not appear.
|
||||
|
||||
```yaml
|
||||
galaxy:
|
||||
@@ -231,9 +231,9 @@ curl -s -H "x-api-key: YOUR_GALAXY_API_KEY" \
|
||||
|
||||
You should see a list of enabled agents with their types. If AI is not configured, this endpoint returns an error indicating that the agent system is not available.
|
||||
|
||||
### Check if ChatGXY Appears in the Sidebar
|
||||
### Check if GalaxyAI Appears in the Sidebar
|
||||
|
||||
Log in to the Galaxy web interface. If AI is properly configured, a **ChatGXY** entry should appear in the Activity Bar on the left side of the screen. If it does not appear:
|
||||
Log in to the Galaxy web interface. If AI is properly configured, a **GalaxyAI** entry should appear in the Activity Bar on the left side of the screen. If it does not appear:
|
||||
|
||||
1. Verify that `inference_services` is set in `galaxy.yml` (or the deprecated `ai_api_key` / `ai_api_base_url`).
|
||||
2. Check that Galaxy was restarted after the configuration change.
|
||||
@@ -251,7 +251,7 @@ This should return `"llm_api_configured": true` when AI is active.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### ChatGXY does not appear in the sidebar
|
||||
### GalaxyAI does not appear in the sidebar
|
||||
|
||||
- Confirm that `inference_services` is set in `galaxy.yml` under the `galaxy:` section (or the deprecated `ai_api_key` / `ai_api_base_url`).
|
||||
- Restart Galaxy after any configuration change.
|
||||
|
||||
@@ -16,10 +16,10 @@ Discover some of the most exciting new capabilities and improvements in Galaxy 2
|
||||
|
||||
*Galaxy 26.0 brings artificial intelligence directly into the Galaxy experience, expanding how users explore data, discover tools, and troubleshoot analyses.*
|
||||
|
||||
ChatGXY: Intelligent Assistance Inside Galaxy
|
||||
---------------------------------------------
|
||||
GalaxyAI: Intelligent Assistance Inside Galaxy
|
||||
----------------------------------------------
|
||||
|
||||
Galaxy introduces **ChatGXY**, a built in AI assistant integrated directly into the interface.
|
||||
Galaxy introduces **GalaxyAI**, a built in AI assistant integrated directly into the interface.
|
||||
|
||||
- **Conversational help**. Ask questions about tools, workflows, results, or errors without leaving Galaxy.
|
||||
- **Error analysis guidance**. Receive contextual explanations and suggestions when jobs fail.
|
||||
@@ -27,12 +27,12 @@ Galaxy introduces **ChatGXY**, a built in AI assistant integrated directly into
|
||||
- **Training discovery**. Find relevant Galaxy Training Network tutorials directly from within Galaxy.
|
||||
- **Extensible architecture**. Built on a flexible agent framework designed to grow with additional specialized AI capabilities over time.
|
||||
|
||||
ChatGXY provides a conversational entry point to Galaxy's AI capabilities and lays the groundwork for connecting Galaxy users to an expanding set of intelligent capabilities.
|
||||
GalaxyAI provides a conversational entry point to Galaxy's AI capabilities and lays the groundwork for connecting Galaxy users to an expanding set of intelligent capabilities.
|
||||
[`#21434 <https://github.com/galaxyproject/galaxy/pull/21434>`__]
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<iframe width="100%" height="360" style="margin-bottom: 1em;" src="https://www.youtube.com/embed/DQsiSbzMQgE?si=NMSpS2KyEO7AmWSM" title="Galaxy 26.0 - ChatGXY" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||
<iframe width="100%" height="360" style="margin-bottom: 1em;" src="https://www.youtube.com/embed/DQsiSbzMQgE?si=NMSpS2KyEO7AmWSM" title="Galaxy 26.0 - GalaxyAI" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
|
||||
|
||||
AI Assisted Notebooks with JupyterLite
|
||||
--------------------------------------
|
||||
|
||||
@@ -128,7 +128,7 @@ class ChatManager:
|
||||
self, trans: ProvidesUserContext, query: str, response_data: Any, agent_type: str = "unknown"
|
||||
) -> ChatExchange:
|
||||
"""
|
||||
Create a general ChatGXY exchange (not job-related) in the database.
|
||||
Create a general GalaxyAI exchange (not job-related) in the database.
|
||||
Stores both the user's query and the full agent response.
|
||||
|
||||
:param query: The user's query
|
||||
|
||||
@@ -1646,31 +1646,31 @@ class NavigatesGalaxy(HasDriverProxy[WaitType]):
|
||||
self.components.invocations.activity.wait_for_and_click()
|
||||
self.components.invocations.activity_expand.wait_for_and_click()
|
||||
|
||||
def navigate_to_chatgxy(self):
|
||||
def navigate_to_galaxyai(self):
|
||||
self.home()
|
||||
self.components.chatgxy.activity.wait_for_and_click()
|
||||
self.components.galaxyai.activity.wait_for_and_click()
|
||||
|
||||
def chatgxy_ensure_new_chat(self):
|
||||
"""Ensure ChatGXY center panel shows an empty conversation."""
|
||||
chatgxy = self.components.chatgxy
|
||||
chatgxy._.wait_for_visible()
|
||||
if len(chatgxy.query_cell.all()) > 0 or len(chatgxy.response_content.all()) > 0:
|
||||
chatgxy.new_chat_button.wait_for_and_click()
|
||||
self._chatgxy_assert_chat_empty()
|
||||
def galaxyai_ensure_new_chat(self):
|
||||
"""Ensure GalaxyAI center panel shows an empty conversation."""
|
||||
galaxyai = self.components.galaxyai
|
||||
galaxyai._.wait_for_visible()
|
||||
if len(galaxyai.query_cell.all()) > 0 or len(galaxyai.response_content.all()) > 0:
|
||||
galaxyai.new_chat_button.wait_for_and_click()
|
||||
self._galaxyai_assert_chat_empty()
|
||||
|
||||
def chatgxy_send_message(self, text):
|
||||
def galaxyai_send_message(self, text):
|
||||
"""Type a message, click send, and wait for the response to appear."""
|
||||
chatgxy = self.components.chatgxy
|
||||
chatgxy.input.wait_for_and_send_keys(text)
|
||||
chatgxy.send_button.wait_for_and_click()
|
||||
chatgxy.loading.wait_for_absent_or_hidden()
|
||||
chatgxy.response_content.wait_for_visible()
|
||||
galaxyai = self.components.galaxyai
|
||||
galaxyai.input.wait_for_and_send_keys(text)
|
||||
galaxyai.send_button.wait_for_and_click()
|
||||
galaxyai.loading.wait_for_absent_or_hidden()
|
||||
galaxyai.response_content.wait_for_visible()
|
||||
|
||||
@retry_during_transitions
|
||||
def _chatgxy_assert_chat_empty(self):
|
||||
chatgxy = self.components.chatgxy
|
||||
assert len(chatgxy.query_cell.all()) == 0
|
||||
assert len(chatgxy.response_content.all()) == 0
|
||||
def _galaxyai_assert_chat_empty(self):
|
||||
galaxyai = self.components.galaxyai
|
||||
assert len(galaxyai.query_cell.all()) == 0
|
||||
assert len(galaxyai.response_content.all()) == 0
|
||||
|
||||
def navigate_to_dataset_error(self, hid):
|
||||
"""Display a dataset and click the error tab."""
|
||||
|
||||
@@ -133,7 +133,7 @@ class ChatAPI:
|
||||
trans: ProvidesUserContext = DependsOnTrans,
|
||||
user: User = DependsOnUser,
|
||||
) -> ChatResponse:
|
||||
"""ChatGXY endpoint - handles both job-based and general chat queries
|
||||
"""GalaxyAI endpoint - handles both job-based and general chat queries
|
||||
|
||||
Backwards compatible with both formats:
|
||||
1. Old format: job_id in query params + payload body with query/context
|
||||
|
||||
@@ -235,8 +235,8 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
|
||||
webapp.add_client_route("/workflow_landings/{uuid}")
|
||||
webapp.add_client_route("/tours")
|
||||
webapp.add_client_route("/tours/{tour_id}")
|
||||
webapp.add_client_route("/chatgxy")
|
||||
webapp.add_client_route("/chatgxy/{exchange_id}")
|
||||
webapp.add_client_route("/galaxyai")
|
||||
webapp.add_client_route("/galaxyai/{exchange_id}")
|
||||
webapp.add_client_route("/user")
|
||||
webapp.add_client_route("/user/notifications{path:.*?}")
|
||||
webapp.add_client_route("/user/{form_id}")
|
||||
|
||||
+31
-31
@@ -1,4 +1,4 @@
|
||||
"""E2E tests for the ChatGXY conversational AI interface.
|
||||
"""E2E tests for the GalaxyAI conversational AI interface.
|
||||
|
||||
Uses the static agent backend for deterministic assertions — no LLM calls.
|
||||
Skipped when agents are not configured (skip_without_agents decorator).
|
||||
@@ -12,7 +12,7 @@ from .framework import (
|
||||
)
|
||||
|
||||
|
||||
class TestChatGXY(SeleniumTestCase):
|
||||
class TestGalaxyAI(SeleniumTestCase):
|
||||
ensure_registered = True
|
||||
|
||||
@skip_without_agents
|
||||
@@ -20,50 +20,50 @@ class TestChatGXY(SeleniumTestCase):
|
||||
def test_chat_greeting_flow(self):
|
||||
"""Activity visible, send greeting, get response, give feedback, check metadata."""
|
||||
self.home()
|
||||
chatgxy = self.components.chatgxy
|
||||
galaxyai = self.components.galaxyai
|
||||
|
||||
# Activity bar icon visible
|
||||
chatgxy.activity.wait_for_visible()
|
||||
galaxyai.activity.wait_for_visible()
|
||||
|
||||
# Navigate, start fresh
|
||||
self.navigate_to_chatgxy()
|
||||
self.chatgxy_ensure_new_chat()
|
||||
self.navigate_to_galaxyai()
|
||||
self.galaxyai_ensure_new_chat()
|
||||
|
||||
# Send greeting
|
||||
self.chatgxy_send_message("Hello!")
|
||||
self.galaxyai_send_message("Hello!")
|
||||
|
||||
# Verify query cell and response
|
||||
assert chatgxy.query_cell.wait_for_text() == "Hello!"
|
||||
assert galaxyai.query_cell.wait_for_text() == "Hello!"
|
||||
|
||||
@retry_assertion_during_transitions
|
||||
def assert_response():
|
||||
assert "Hello" in chatgxy.response_content.wait_for_text()
|
||||
assert "Hello" in galaxyai.response_content.wait_for_text()
|
||||
|
||||
assert_response()
|
||||
|
||||
# Agent indicator and metadata tags present
|
||||
chatgxy.agent_indicator.wait_for_visible()
|
||||
assert len(chatgxy.meta_tag.all()) >= 1
|
||||
galaxyai.agent_indicator.wait_for_visible()
|
||||
assert len(galaxyai.meta_tag.all()) >= 1
|
||||
|
||||
# Feedback
|
||||
chatgxy.feedback_up.wait_for_and_click()
|
||||
assert "Thanks" in chatgxy.feedback_ack.wait_for_text()
|
||||
galaxyai.feedback_up.wait_for_and_click()
|
||||
assert "Thanks" in galaxyai.feedback_ack.wait_for_text()
|
||||
|
||||
@skip_without_agents
|
||||
@selenium_test
|
||||
def test_multi_turn_and_new_chat(self):
|
||||
"""Two queries build up conversation, 'New' resets it."""
|
||||
self.navigate_to_chatgxy()
|
||||
self.chatgxy_ensure_new_chat()
|
||||
chatgxy = self.components.chatgxy
|
||||
self.navigate_to_galaxyai()
|
||||
self.galaxyai_ensure_new_chat()
|
||||
galaxyai = self.components.galaxyai
|
||||
|
||||
self.chatgxy_send_message("Hello!")
|
||||
self.chatgxy_send_message("How do I analyze RNA-seq data?")
|
||||
self.galaxyai_send_message("Hello!")
|
||||
self.galaxyai_send_message("How do I analyze RNA-seq data?")
|
||||
|
||||
@retry_assertion_during_transitions
|
||||
def assert_two_exchanges():
|
||||
assert len(chatgxy.query_cell.all()) == 2
|
||||
responses = chatgxy.response_content.all()
|
||||
assert len(galaxyai.query_cell.all()) == 2
|
||||
responses = galaxyai.response_content.all()
|
||||
assert len(responses) >= 2
|
||||
# Second response should be domain-specific
|
||||
assert "HISAT2" in responses[-1].text or "RNA-seq" in responses[-1].text
|
||||
@@ -71,8 +71,8 @@ class TestChatGXY(SeleniumTestCase):
|
||||
assert_two_exchanges()
|
||||
|
||||
# New chat resets
|
||||
chatgxy.new_chat_button.wait_for_and_click()
|
||||
self._chatgxy_assert_chat_empty()
|
||||
galaxyai.new_chat_button.wait_for_and_click()
|
||||
self._galaxyai_assert_chat_empty()
|
||||
|
||||
@skip_without_agents
|
||||
@selenium_test
|
||||
@@ -81,21 +81,21 @@ class TestChatGXY(SeleniumTestCase):
|
||||
# Clear any existing chat history so test is deterministic
|
||||
self.api_delete("chat/history")
|
||||
|
||||
self.navigate_to_chatgxy()
|
||||
chatgxy = self.components.chatgxy
|
||||
history = chatgxy.history_panel
|
||||
self.navigate_to_galaxyai()
|
||||
galaxyai = self.components.galaxyai
|
||||
history = galaxyai.history_panel
|
||||
|
||||
# Create first chat
|
||||
self.chatgxy_ensure_new_chat()
|
||||
self.chatgxy_send_message("Hello!")
|
||||
self.galaxyai_ensure_new_chat()
|
||||
self.galaxyai_send_message("Hello!")
|
||||
|
||||
# Create second chat
|
||||
self.chatgxy_ensure_new_chat()
|
||||
self.chatgxy_send_message("How do I analyze RNA-seq data?")
|
||||
self.galaxyai_ensure_new_chat()
|
||||
self.galaxyai_send_message("How do I analyze RNA-seq data?")
|
||||
|
||||
# Switch sidebar away from chatgxy then back to force ChatHistoryPanel remount
|
||||
# Switch sidebar away from galaxyai then back to force ChatHistoryPanel remount
|
||||
self.components.tools.activity.wait_for_and_click()
|
||||
chatgxy.activity.wait_for_and_click()
|
||||
galaxyai.activity.wait_for_and_click()
|
||||
history._.wait_for_visible()
|
||||
|
||||
# Wait for history items to appear
|
||||
Reference in New Issue
Block a user