Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion redisinsight/api/config/features-config.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": 11,
"version": 12,
"features": {
"appUpdateStrategySettings": {
"flag": true,
Expand Down Expand Up @@ -33,6 +33,11 @@
}
]
},
"agentMemory": {
"flag": true,
"perc": [[0, 100]],
"filters": []
},
"insightsRecommendations": {
"flag": true,
"perc": [[0, 100]]
Expand Down
1 change: 1 addition & 0 deletions redisinsight/api/src/modules/feature/constants/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export enum KnownFeatures {
DocumentationChat = 'documentationChat',
DatabaseChat = 'databaseChat',
Rdi = 'redisDataIntegration',
AgentMemory = 'agentMemory',
HashFieldExpiration = 'hashFieldExpiration',
EnhancedCloudUI = 'enhancedCloudUI',
DatabaseManagement = 'databaseManagement',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ export const knownFeatures: Record<KnownFeatures, IFeatureFlag> = {
name: KnownFeatures.Rdi,
storage: FeatureStorage.Database,
},
[KnownFeatures.AgentMemory]: {
name: KnownFeatures.AgentMemory,
storage: FeatureStorage.Database,
},
[KnownFeatures.EnhancedCloudUI]: {
name: KnownFeatures.EnhancedCloudUI,
storage: FeatureStorage.Database,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class FeatureFlagProvider {
KnownFeatures.Rdi,
new CommonFlagStrategy(this.featuresConfigService, this.settingsService),
);
this.strategies.set(
KnownFeatures.AgentMemory,
new CommonFlagStrategy(this.featuresConfigService, this.settingsService),
);
this.strategies.set(
KnownFeatures.CloudSso,
new CloudSsoFlagStrategy(
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions redisinsight/ui/src/components/base/utils/VisuallyHidden.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { HTMLAttributes } from 'react'
import styled, { css } from 'styled-components'

/**
* Standard screen-reader-only ruleset: the element stays in the
* accessibility tree but is removed from the visual layout.
* Apply to any styled component via `${visuallyHiddenCss}` or render
* the ready-made <VisuallyHidden> span.
*/
export const visuallyHiddenCss = css`
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
`

export const VisuallyHidden = styled.span<HTMLAttributes<HTMLSpanElement>>`
${visuallyHiddenCss}
`
7 changes: 7 additions & 0 deletions redisinsight/ui/src/components/home-tabs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ const tabs: HomeTab[] = [
path: Pages.rdi,
featureFlag: FeatureFlags.rdi,
},
{
value: 'agent-memory',
label: 'Agent Memory',
content: null,
path: Pages.agentMemory,
featureFlag: FeatureFlags.agentMemory,
},
]

export { tabs }
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import RdiPage from 'uiSrc/pages/rdi/home'
import RdiInstancePage from 'uiSrc/pages/rdi/instance'
import RdiStatisticsPage from 'uiSrc/pages/rdi/statistics'
import PipelineManagementPage from 'uiSrc/pages/rdi/pipeline-management'
import AgentMemoryPage from 'uiSrc/pages/agent-memory/home'
import AgentMemoryWorkspacePage from 'uiSrc/pages/agent-memory/workspace'
import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES } from './sub-routes'
import COMMON_ROUTES from './commonRoutes'
import { getRouteIncludedByEnv, LAZY_LOAD } from '../config'
Expand Down Expand Up @@ -67,6 +69,10 @@ const LazyRdiStatisticsPage = lazy(() => import('uiSrc/pages/rdi/statistics'))
const LazyPipelineManagementPage = lazy(
() => import('uiSrc/pages/rdi/pipeline-management'),
)
const LazyAgentMemoryPage = lazy(() => import('uiSrc/pages/agent-memory/home'))
const LazyAgentMemoryWorkspacePage = lazy(
() => import('uiSrc/pages/agent-memory/workspace'),
)

const INSTANCE_ROUTES: IRoute[] = [
{
Expand Down Expand Up @@ -186,6 +192,19 @@ const ROUTES: IRoute[] = [
routes: RDI_INSTANCE_ROUTES,
featureFlag: FeatureFlags.rdi,
},
{
path: Pages.agentMemory,
component: LAZY_LOAD ? LazyAgentMemoryPage : AgentMemoryPage,
exact: true,
featureFlag: FeatureFlags.agentMemory,
},
{
path: Pages.agentMemoryWorkspace(':endpointId', ':tab?'),
component: LAZY_LOAD
? LazyAgentMemoryWorkspacePage
: AgentMemoryWorkspacePage,
featureFlag: FeatureFlags.agentMemory,
},
]),
{
path: '/:instanceId',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@
</Text>
),
}),
ADDED_NEW_AGENT_MEMORY_ENDPOINT: (endpointName: string) => ({

Check warning on line 63 in redisinsight/ui/src/components/notifications/success-messages.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🕹️ Function is not covered

Warning! Not covered function
title: i18n.t('notification.success.addedAgentMemoryEndpoint.title'),
message: (
<Text component="span">
<Trans
i18nKey="notification.success.addedAgentMemoryEndpoint.message"
values={{ name: escapeTrans(formatNameShort(endpointName)) }}
components={{ bold }}
/>
</Text>
),
}),

Check warning on line 74 in redisinsight/ui/src/components/notifications/success-messages.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement
DELETE_INSTANCE: (instanceName: string) => ({
title: i18n.t('notification.success.deleteInstance.title'),
message: (
Expand Down
10 changes: 10 additions & 0 deletions redisinsight/ui/src/constants/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,16 @@ enum ApiEndpoints {
RDI_PIPELINE_STOP = 'pipeline/stop',
RDI_PIPELINE_START = 'pipeline/start',
RDI_PIPELINE_RESET = 'pipeline/reset',

AGENT_MEMORY_ENDPOINTS = 'agent-memory',
AGENT_MEMORY_CONNECT = 'connect',
AGENT_MEMORY_SESSIONS = 'sessions',
AGENT_MEMORY_WORKING_MEMORY = 'working-memory',
AGENT_MEMORY_LTM_SEARCH = 'long-term-memory/search',
AGENT_MEMORY_LTM = 'long-term-memory',
AGENT_MEMORY_DISCOVERY = 'discovery',
AGENT_MEMORY_CONFIG = 'config',
AGENT_MEMORY_SUMMARY_VIEWS = 'summary-views',
}

export enum CustomHeaders {
Expand Down
1 change: 1 addition & 0 deletions redisinsight/ui/src/constants/featureFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum FeatureFlags {
documentationChat = 'documentationChat',
envDependent = 'envDependent',
rdi = 'redisDataIntegration',
agentMemory = 'agentMemory',
hashFieldExpiration = 'hashFieldExpiration',
enhancedCloudUI = 'enhancedCloudUI',
cloudAds = 'cloudAds',
Expand Down
7 changes: 7 additions & 0 deletions redisinsight/ui/src/constants/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
const sentinel = '/sentinel'
const azure = '/azure'
const rdi = '/integrate'
const agentMemory = '/agent-memory'

// Query-param keys used to deep-link into the home page's edit-database dialog
// and (optionally) reveal one of its fields.
Expand Down Expand Up @@ -89,4 +90,10 @@
rdiPipelineJobs: (rdiInstance: string, jobName: string) =>
`${rdi}/${rdiInstance}/${PageNames.rdiPipelineManagement}/${PageNames.rdiPipelineJobs}/${jobName}`,
rdiStatistics: (rdiInstance: string) => `${rdi}/${rdiInstance}/statistics`,
// agent memory pages
agentMemory,
agentMemoryWorkspace: (endpointId: string, tab?: string) =>
tab
? `${agentMemory}/${endpointId}/${tab}`
: `${agentMemory}/${endpointId}`,

Check warning on line 98 in redisinsight/ui/src/constants/pages.ts

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🌿 Branch is not covered

Warning! Not covered branch
}
3 changes: 3 additions & 0 deletions redisinsight/ui/src/constants/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ enum BrowserStorageItem {
treeViewSort = 'treeViewSort',
treeViewPrefixLength = 'treeViewDelimiterPrefixLength',
autoRefreshRate = 'autoRefreshRate',
autoRefreshEnabled = 'autoRefreshEnabled',
bulkActionDeleteId = 'bulkActionDeleteId',
dbConfig = 'dbConfig_',
RunQueryMode = 'RunQueryMode',
Expand Down Expand Up @@ -50,6 +51,8 @@ enum BrowserStorageItem {
prodModeCtaActioned = 'prodModeCtaActioned',
whatsNewLastVersionSeen = 'whatsNewLastVersionSeen',
valueDecoderRules = 'valueDecoderRules_',
agentMemoryPanelSizes = 'agentMemoryPanelSizes',
agentMemoryLtmPanelSizes = 'agentMemoryLtmPanelSizes',
}

export default BrowserStorageItem
Expand Down
2 changes: 2 additions & 0 deletions redisinsight/ui/src/i18n/locales/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@
"notification.infinite.successDeployPipeline.message": "Поздравления!",
"notification.success.addLibrary.message": "<bold>{{name}}</bold> беше добавена.",
"notification.success.addLibrary.title": "Библиотеката беше добавена",
"notification.success.addedAgentMemoryEndpoint.message": "<bold>{{name}}</bold> беше добавена към RedisInsight.",
"notification.success.addedAgentMemoryEndpoint.title": "Крайната точка за агентна памет беше добавена",
"notification.success.addedInstance.message": "<bold>{{name}}</bold> беше добавена към Redis Insight.",
"notification.success.addedInstance.title": "Базата данни беше добавена",
"notification.success.addedKey.message": "<bold>{{name}}</bold> беше добавен.",
Expand Down
2 changes: 2 additions & 0 deletions redisinsight/ui/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1413,6 +1413,8 @@
"notification.infinite.successDeployPipeline.message": "Congratulations!",
"notification.success.addLibrary.message": "<bold>{{name}}</bold> has been added.",
"notification.success.addLibrary.title": "Library has been added",
"notification.success.addedAgentMemoryEndpoint.message": "<bold>{{name}}</bold> has been added to RedisInsight.",
"notification.success.addedAgentMemoryEndpoint.title": "Agent memory endpoint has been added",
"notification.success.addedInstance.message": "<bold>{{name}}</bold> has been added to Redis Insight.",
"notification.success.addedInstance.title": "Database has been added",
"notification.success.addedKey.message": "<bold>{{name}}</bold> has been added.",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import styled from 'styled-components'
import { Theme } from 'uiSrc/components/base/theme/types'
import { FlexItem } from 'uiSrc/components/base/layout/flex'
import { Page } from 'uiSrc/components/base/layout/page'

export const HomePage = styled(Page)`
padding: 1px ${({ theme }: { theme: Theme }) => theme.core.space.space200}
${({ theme }: { theme: Theme }) => theme.core.space.space200};
`

export const EmptyPageContainer = styled(FlexItem)`
padding: ${({ theme }: { theme: Theme }) => theme.core.space.space300};
border: 1px solid
${({ theme }: { theme: Theme }) => theme.semantic.color.border.neutral500};
border-radius: ${({ theme }: { theme: Theme }) =>
theme.components.card.borderRadius};
`
122 changes: 122 additions & 0 deletions redisinsight/ui/src/pages/agent-memory/home/AgentMemoryPage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React, { useEffect, useState } from 'react'
import { useHistory } from 'react-router-dom'

import { useAppSelector } from 'uiSrc/slices/hooks'
import { dispatch } from 'uiSrc/slices/store'
import {
agentMemoryEndpointsSelector,
connectEndpointAction,
createEndpointAction,
editEndpointAction,
fetchEndpointsAction,
} from 'uiSrc/slices/agentMemory/endpoints'
import { AgentMemoryEndpoint } from 'uiSrc/slices/interfaces/agentMemory'
import { Pages } from 'uiSrc/constants'
import { setTitle, Nullable } from 'uiSrc/utils'
import HomePageTemplate from 'uiSrc/templates/home-page-template'
import { PageBody } from 'uiSrc/components/base/layout/page'
import { Row } from 'uiSrc/components/base/layout/flex'
import { Spacer } from 'uiSrc/components/base/layout/spacer'
import { PrimaryButton } from 'uiSrc/components/base/forms/buttons'
import { PlusIcon } from 'uiSrc/components/base/icons'
import { RiBadge } from 'uiSrc/components/base/display/badge/RiBadge'
import { Title } from 'uiSrc/components/base/text'

import EndpointsList from './components/endpoints-list/EndpointsList'
import EmptyMessage from './components/empty-message/EmptyMessage'
import EndpointConnectionFormWrapper from './components/connection-form/EndpointConnectionFormWrapper'
import * as S from './AgentMemoryPage.styles'

const PAGE_TITLE = 'Agent Memory'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Localize the new Agent Memory interface

When RedisInsight is running in Bulgarian, this title and the other newly added Agent Memory labels, buttons, placeholders, errors, and dialog text remain in English because they are literals rather than t/Trans keys; only the success notification was added to the locale files. Move the new user-facing copy into matching en.json and bg.json keys so the entire feature follows the selected locale.

AGENTS.md reference: AGENTS.md:L127-L127

Useful? React with 👍 / 👎.


const AgentMemoryPage = () => {
const history = useHistory()
const { data, loading, loadingChanging } = useAppSelector(
agentMemoryEndpointsSelector,
)

const [isFormOpen, setIsFormOpen] = useState(false)
const [editEndpoint, setEditEndpoint] =
useState<Nullable<AgentMemoryEndpoint>>(null)

const hideList = data.length === 0 && !loading && !loadingChanging

useEffect(() => {
dispatch(fetchEndpointsAction())
setTitle(PAGE_TITLE)
}, [])

const handleOpenForm = () => {
setEditEndpoint(null)
setIsFormOpen(true)
}

const handleCloseForm = () => {
setEditEndpoint(null)
setIsFormOpen(false)
}

const handleEdit = (endpoint: AgentMemoryEndpoint) => {
setEditEndpoint(endpoint)
setIsFormOpen(true)
}

const handleConnect = (endpoint: AgentMemoryEndpoint) => {
dispatch(
connectEndpointAction(endpoint.id, () =>
history.push(Pages.agentMemoryWorkspace(endpoint.id)),
),
)
}

const handleFormSubmit = (endpoint: Partial<AgentMemoryEndpoint>) => {
if (editEndpoint) {
dispatch(editEndpointAction(editEndpoint.id, endpoint, handleCloseForm))
} else {
dispatch(createEndpointAction(endpoint, handleCloseForm))
}
}

return (
<HomePageTemplate>
<S.HomePage className="homePage">
<PageBody component="div">
<Row align="center" justify="between" grow={false}>
<Row align="center" gap="m" grow={false}>
<Title size="M">{PAGE_TITLE}</Title>
<RiBadge
label="Preview"
variant="notice"
data-testid="agent-memory-preview-badge"
/>
</Row>
{!hideList && (
<PrimaryButton
data-testid="agent-memory-add-endpoint-button"
icon={PlusIcon}
onClick={handleOpenForm}
>
Agent memory endpoint
</PrimaryButton>
)}
</Row>
<Spacer size="m" />
{hideList ? (
<EmptyMessage onAddClick={handleOpenForm} />
) : (
<EndpointsList onEdit={handleEdit} onConnect={handleConnect} />
)}
<EndpointConnectionFormWrapper
isOpen={isFormOpen}
onSubmit={handleFormSubmit}
onCancel={handleCloseForm}
editEndpoint={editEndpoint}
isLoading={loading || loadingChanging}
/>
</PageBody>
</S.HomePage>
</HomePageTemplate>
)
}

export default AgentMemoryPage
Loading
Loading