diff --git a/nginx/nginx.tmpl b/nginx/nginx.tmpl index 3039283c7..998e254d0 100644 --- a/nginx/nginx.tmpl +++ b/nginx/nginx.tmpl @@ -39,22 +39,6 @@ http { location /v1/healthz { return 200 'OK'; } - location ~ ^/teams/([^/]+)/agents/([^/]+)/(.*)$ { - set $team_id $1; - set $agent_name $2; - set $agent_path $3; - resolver ${KUBE_DNS_SERVICE_HOST} valid=10s; - proxy_pass http://$agent_name.team-$team_id.svc.cluster.local:9099/$agent_path$is_args$args; - proxy_http_version 1.1; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - # Support for streaming responses - proxy_buffering off; - proxy_cache off; - chunked_transfer_encoding on; - } location ~* \.(?:css|js|eot|woff|woff2|ttf|svg|otf) { # Enable GZip for static files gzip_static on; diff --git a/public/assets/agents_icon.svg b/public/assets/agents_icon.svg deleted file mode 100644 index 33621541e..000000000 --- a/public/assets/agents_icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/assets/knowledgebases_icon.svg b/public/assets/knowledgebases_icon.svg deleted file mode 100644 index 23f69af30..000000000 --- a/public/assets/knowledgebases_icon.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/i18n/en/common.json b/public/i18n/en/common.json index 5e8afff77..8a19d89f9 100644 --- a/public/i18n/en/common.json +++ b/public/i18n/en/common.json @@ -91,14 +91,6 @@ "Code-repository_plural": "Code Repositories", "TITLE_CODE_REPOSITORY": "Code repository details", "TITLE_CODE_REPOSITORIES": "Code repositories - {{scope}}", - "Knowledge-base": "Knowledge Base", - "Knowledge-base_plural": "Knowledge Bases", - "TITLE_KNOWLEDGE_BASE": "Knowledge base details", - "TITLE_KNOWLEDGE_BASES": "Knowledge bases - {{scope}}", - "Agent": "Agent", - "Agent_plural": "Agents", - "TITLE_AGENT": "Agent details", - "TITLE_AGENTS": "Agents - {{scope}}", "TITLE_NETWORK_POLICY": "Network policy details", "TITLE_NETWORK_POLICIES": "Network policies - {{scope}}" } diff --git a/src/components/AgentPlayground.tsx b/src/components/AgentPlayground.tsx deleted file mode 100644 index a0895c9aa..000000000 --- a/src/components/AgentPlayground.tsx +++ /dev/null @@ -1,331 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react' -import { Alert, Box, IconButton, TextField, Typography, keyframes } from '@mui/material' -import SendIcon from '@mui/icons-material/Send' -import DeleteIcon from '@mui/icons-material/Delete' -import StopIcon from '@mui/icons-material/StopCircle' -import Markdown from './Markdown' -import { Paper } from './Paper' -import Iconify from './Iconify' - -const thinkingAnimation = keyframes` - 0%, 60%, 100% { - opacity: 0.3; - } - 30% { - opacity: 1; - } -` - -interface Message { - role: 'user' | 'assistant' - content: string - id: string -} - -interface AgentPlaygroundProps { - teamId: string - agentName: string -} - -export function AgentPlayground({ teamId, agentName }: AgentPlaygroundProps): React.ReactElement { - const [messages, setMessages] = useState([]) - const [input, setInput] = useState('') - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) - const messagesEndRef = useRef(null) - const messagesContainerRef = useRef(null) - const abortControllerRef = useRef(null) - - const scrollToBottom = () => { - if (messagesContainerRef.current) messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight - } - - useEffect(() => { - scrollToBottom() - }, [messages]) - - const handleStop = () => { - if (abortControllerRef.current) { - abortControllerRef.current.abort() - abortControllerRef.current = null - setLoading(false) - // Remove the empty assistant message if it exists - setMessages((prev) => { - const lastMessage = prev[prev.length - 1] - if (lastMessage?.role === 'assistant' && !lastMessage.content) return prev.slice(0, -1) - - return prev - }) - } - } - - const handleSend = async () => { - if (!input.trim() || loading) return - - const userMessage: Message = { role: 'user', content: input.trim(), id: `user-${Date.now()}` } - const assistantId = `assistant-${Date.now()}` - const newMessages = [...messages, userMessage] - - // Immediately add user message and empty assistant message for thinking animation - setMessages([...newMessages, { role: 'assistant', content: '', id: assistantId }]) - setInput('') - setLoading(true) - setError(null) - - // Create new abort controller for this request - abortControllerRef.current = new AbortController() - - try { - // Call agent service through nginx proxy to handle http and mixed-content issues - // In development: use /agent proxy (port-forward to localhost:9099) - // In cluster: use /teams/{teamId}/agents/{agentName} proxy (nginx routes to internal service) - const isDev = process.env.NODE_ENV === 'development' - const agentServiceUrl = isDev - ? `/agent/v1/chat/completions` - : `/teams/${teamId}/agents/${agentName}/v1/chat/completions` - - const requestBody = { - messages: newMessages.map((msg) => ({ role: msg.role, content: msg.content })), - stream: true, - model: 'rag-pipeline', - } - - const response = await fetch(agentServiceUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify(requestBody), - signal: abortControllerRef.current.signal, - }) - - if (!response.ok) { - const errorData = await response.json().catch(() => ({ error: { message: 'Unknown error' } })) - const errorMessage = errorData?.error?.message || `Error: ${response.status}` - throw new Error(typeof errorMessage === 'string' ? errorMessage : 'Unknown error') - } - - // Handle streaming response - const reader = response.body?.getReader() - const decoder = new TextDecoder() - - if (reader) { - // Process streaming response - const processStream = async () => { - let accumulatedContent = '' - // eslint-disable-next-line no-constant-condition - while (true) { - // eslint-disable-next-line no-await-in-loop - const { done, value } = await reader.read() - if (done) break - - const chunk = decoder.decode(value, { stream: true }) - const lines = chunk.split('\n') - - // eslint-disable-next-line no-loop-func - lines.forEach((line) => { - if (line.startsWith('data: ')) { - const data = line.slice(6) - if (data === '[DONE]') return - - try { - const parsed = JSON.parse(data) - const content = parsed.choices?.[0]?.delta?.content || '' - if (content) { - accumulatedContent += content - const currentContent = accumulatedContent - setMessages((prev) => { - const updated = [...prev] - const lastIndex = updated.length - 1 - if (lastIndex >= 0 && updated[lastIndex].id === assistantId) - updated[lastIndex] = { ...updated[lastIndex], content: currentContent } - return updated - }) - } - } catch { - // Ignore JSON parse errors for malformed chunks - } - } - }) - } - } - - await processStream() - } else { - // Non-streaming response - const data = await response.json() - const assistantContent = data.choices?.[0]?.message?.content || 'No response' - setMessages([...newMessages, { role: 'assistant', content: assistantContent, id: assistantId }]) - } - } catch (err) { - // Don't show error if request was aborted by user - if (err instanceof Error && err.name === 'AbortError') return - - const errorMessage = err instanceof Error ? err.message : 'Failed to send message' - setError(errorMessage) - } finally { - setLoading(false) - abortControllerRef.current = null - } - } - - const handleClear = () => { - setMessages([]) - setError(null) - } - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault() - handleSend() - } - } - - return ( - - - {/* Header */} - - Agent Playground - - - - - - {/* Messages Area */} - - {messages.length === 0 ? ( - - - - Ask your agent a question to start evaluating. - - - ) : ( - messages.map((message) => ( - - - - {message.role === 'user' ? 'You' : 'Agent'} - - {(() => { - // Show thinking animation for empty assistant message while loading - if (message.role === 'assistant' && !message.content && loading) { - return ( - - - - - - ) - } - - // Render assistant message with markdown - if (message.role === 'assistant') { - return ( - - ) - } - - return ( - - {message.content} - - ) - })()} - - - )) - )} -
- - - {/* Error Display */} - {error && ( - setError(null)}> - {error} - - )} - - {/* Input Area */} - - setInput(e.target.value)} - onKeyDown={handleKeyDown} - placeholder='Type your message...' - disabled={loading} - variant='outlined' - size='small' - /> - {loading ? ( - - - - ) : ( - - - - )} - - - - ) -} diff --git a/src/components/NavConfig.tsx b/src/components/NavConfig.tsx index c39597a03..6883203c7 100644 --- a/src/components/NavConfig.tsx +++ b/src/components/NavConfig.tsx @@ -16,7 +16,6 @@ export default function NavConfig() { const oboTeamId = sessionOboTeamId || localOboTeamId || undefined const hasExternalIDP = settings?.otomi?.hasExternalIDP ?? false const isManaged = settings?.otomi?.isPreInstalled ?? false - const aiEnabled = settings?.otomi?.aiEnabled ?? false const hasApiServerConfigured = settings?.cluster?.apiServer ?? false const downloadOpts = { @@ -51,18 +50,6 @@ export default function NavConfig() { path: `/catalogs/${oboTeamId}`, icon: getIcon('developer_guide_icon.svg'), }, - { - title: 'Agents', - path: `/teams/${oboTeamId}/agents`, - icon: getIcon('agents_icon.svg'), - hidden: true, - }, - { - title: 'Knowledge Bases', - path: `/teams/${oboTeamId}/knowledge-bases`, - icon: getIcon('knowledgebases_icon.svg'), - hidden: true, - }, { title: 'Code Repositories', path: `/teams/${oboTeamId}/code-repositories`, diff --git a/src/pages/agents/create-edit/AgentsCreateEditPage.tsx b/src/pages/agents/create-edit/AgentsCreateEditPage.tsx deleted file mode 100644 index 80116f6ba..000000000 --- a/src/pages/agents/create-edit/AgentsCreateEditPage.tsx +++ /dev/null @@ -1,226 +0,0 @@ -import { Grid } from '@mui/material' -import { TextField } from 'components/forms/TextField' -import { Autocomplete } from 'components/forms/Autocomplete' -import { AutoResizableTextarea } from 'components/forms/TextArea' -import { LandingHeader } from 'components/LandingHeader' -import PaperLayout from 'layouts/Paper' -import React, { useEffect } from 'react' -import { FormProvider, Resolver, useForm } from 'react-hook-form' -import { yupResolver } from '@hookform/resolvers/yup' -import { Redirect, RouteComponentProps } from 'react-router-dom' -import { isEqual } from 'lodash' -import { - CreateAplAgentApiArg, - useCreateAplAgentMutation, - useDeleteAplAgentMutation, - useEditAplAgentMutation, - useGetAiModelsQuery, - useGetAplAgentQuery, - useGetAplKnowledgeBasesQuery, -} from 'redux/otomiApi' -import { useTranslation } from 'react-i18next' -import FormRow from 'components/forms/FormRow' -import { useAppSelector } from 'redux/hooks' -import Section from 'components/Section' -import DeleteButton from 'components/DeleteButton' -import { LoadingButton } from '@mui/lab' -import { Divider } from 'components/Divider' -import { AgentPlayground } from 'components/AgentPlayground' -import { agentSchema } from './create-edit-agents.validator' - -interface Params { - teamId: string - agentName?: string -} - -export default function AgentsCreateEditPage({ - match: { - params: { teamId, agentName }, - }, -}: RouteComponentProps): React.ReactElement { - const { t } = useTranslation() - - const [create, { isLoading: isLoadingCreate, isSuccess: isSuccessCreate }] = useCreateAplAgentMutation() - const [update, { isLoading: isLoadingUpdate, isSuccess: isSuccessUpdate }] = useEditAplAgentMutation() - const [del, { isLoading: isLoadingDelete, isSuccess: isSuccessDelete }] = useDeleteAplAgentMutation() - const { data, isLoading, isFetching, isError, refetch } = useGetAplAgentQuery( - { teamId, agentName }, - { skip: !agentName }, - ) - const { data: aiModels } = useGetAiModelsQuery() - const { data: knowledgeBases } = useGetAplKnowledgeBasesQuery({ teamId }) - - const isDirty = useAppSelector(({ global: { isDirty } }) => isDirty) - useEffect(() => { - if (isDirty !== false) return - if (!isFetching) refetch() - }, [isDirty]) - - type FormType = CreateAplAgentApiArg['body'] - - const defaultValues: FormType = { - kind: 'AkamaiAgent' as const, - metadata: { - name: '', - }, - spec: { - foundationModel: '', - agentInstructions: '', - tools: [], - }, - } - - const methods = useForm({ - resolver: yupResolver(agentSchema) as unknown as Resolver, - defaultValues, - }) - - const { - register, - reset, - handleSubmit, - watch, - formState: { errors }, - setValue, - } = methods - - useEffect(() => { - if (data) reset(data) - }, [data, reset]) - - const onSubmit = (formData: FormType) => { - const body = { ...formData } - - if (agentName) update({ teamId, agentName, body }) - else create({ teamId, body }) - } - - const mutating = isLoadingCreate || isLoadingUpdate || isLoadingDelete - if (!mutating && (isSuccessCreate || isSuccessUpdate || isSuccessDelete)) - return - - const loading = isLoading - - if (loading) return - - return ( - - - - -
-
- - { - const value = e.target.value - setValue('metadata.name', value) - }} - error={!!errors.metadata?.name} - helperText={errors.metadata?.name?.message?.toString()} - disabled={!!agentName} - /> - - - - - - model.spec.modelType === 'foundation') - .map((model) => model.metadata.name) || [] - } - getOptionLabel={(option) => { - const model = aiModels?.find((m) => m.metadata.name === option) - return model?.spec.displayName || option - }} - value={watch('spec.foundationModel') || null} - onChange={(_, value) => { - setValue('spec.foundationModel', value || '') - }} - errorText={errors.spec?.foundationModel?.message?.toString()} - helperText={errors.spec?.foundationModel?.message?.toString()} - /> - - - - - - kb.metadata.name) || []} - value={watch('spec.tools')?.find((tool) => tool.type === 'knowledgeBase')?.name || ''} - onChange={(_, value) => { - const currentTools = watch('spec.tools') || [] - const nonKbTools = currentTools.filter((tool) => tool.type !== 'knowledgeBase') - const updatedTools = value ? [...nonKbTools, { type: 'knowledgeBase', name: value }] : nonKbTools - setValue('spec.tools', updatedTools) - }} - /> - - - - - - { - const value = e.target.value - setValue('spec.agentInstructions', value) - }} - error={!!errors.spec?.agentInstructions} - value={watch('spec.agentInstructions') || ''} - /> - -
- - {agentName && ( - del({ teamId, agentName })} - resourceName={watch('metadata.name')} - resourceType='agent' - data-cy='button-delete-agent' - sx={{ float: 'right', textTransform: 'capitalize', ml: 2 }} - loading={isLoadingDelete} - disabled={isLoadingDelete || isLoadingCreate || isLoadingUpdate} - /> - )} - - {agentName ? 'Save Changes' : 'Create Agent'} - - -
- {agentName && } -
-
- ) -} diff --git a/src/pages/agents/create-edit/create-edit-agents.validator.ts b/src/pages/agents/create-edit/create-edit-agents.validator.ts deleted file mode 100644 index 44a6c15f8..000000000 --- a/src/pages/agents/create-edit/create-edit-agents.validator.ts +++ /dev/null @@ -1,21 +0,0 @@ -import * as yup from 'yup' - -// Schema for Agent form validation -export const agentSchema = yup.object({ - kind: yup.string().oneOf(['AkamaiAgent']).required(), - metadata: yup.object({ - name: yup - .string() - .required('Agent name is required') - .min(2, 'Agent name must be at least 2 characters') - .matches( - /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/, - 'Name must start and end with a lowercase letter or number, and can only contain lowercase letters, numbers, and hyphens', - ), - }), - spec: yup.object({ - foundationModel: yup.string().required('Please select a foundation model'), - knowledgeBase: yup.string().optional(), - agentInstructions: yup.string().required('Please enter agent instructions'), - }), -}) diff --git a/src/pages/agents/index.tsx b/src/pages/agents/index.tsx deleted file mode 100644 index 7e029d6bd..000000000 --- a/src/pages/agents/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import AgentsOverviewPage from './overview/AgentsOverviewPage' -import AgentsCreateEditPage from './create-edit/AgentsCreateEditPage' - -export default { - AgentsOverviewPage, - AgentsCreateEditPage, -} diff --git a/src/pages/agents/overview/AgentsOverviewPage.tsx b/src/pages/agents/overview/AgentsOverviewPage.tsx deleted file mode 100644 index 915cc62aa..000000000 --- a/src/pages/agents/overview/AgentsOverviewPage.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import PaperLayout from 'layouts/Paper' -import React, { useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import { RouteComponentProps } from 'react-router-dom' -import { getRole } from 'utils/data' -import { useGetAplAgentsQuery } from 'redux/otomiApi' -import { useAppSelector } from 'redux/hooks' -import { HeadCell } from '../../../components/EnhancedTable' -import RLink from '../../../components/Link' -import ListTable from '../../../components/ListTable' - -const getAgentName = (): CallableFunction => - function (row: any): string | React.ReactElement { - const { teamId, name }: { teamId: string; name: string } = row - const path = `/teams/${teamId}/agents/${encodeURIComponent(name)}` - return ( - - {name} - - ) - } - -const getStatus = (): CallableFunction => - function (row: any): string { - const { status } = row - return status?.phase || 'Unknown' - } - -const getFoundationModel = (): CallableFunction => - function (row: any): string { - const { foundationModel } = row - return foundationModel || 'N/A' - } - -interface Params { - teamId: string -} - -export default function AgentsOverviewPage({ - match: { - params: { teamId }, - }, -}: RouteComponentProps): React.ReactElement { - const { t } = useTranslation() - - const { data: agents, isLoading, isFetching, refetch } = useGetAplAgentsQuery({ teamId }) - - const isDirty = useAppSelector(({ global: { isDirty } }) => isDirty) - useEffect(() => { - if (isDirty !== false) return - if (!isFetching) refetch() - }, [isDirty]) - - // Transform API response to match table format - const transformedData = - agents?.map((agent) => ({ - name: agent.metadata.name, - teamId, - status: agent.status, - foundationModel: agent.spec.foundationModel, - })) || [] - - const headCells: HeadCell[] = [ - { - id: 'name', - label: t('Name'), - renderer: getAgentName(), - }, - { - id: 'status', - label: t('Status'), - renderer: getStatus(), - }, - { - id: 'foundationModel', - label: t('Foundation Model'), - renderer: getFoundationModel(), - }, - ] - - const customButtonText = () => Create Agent - - const comp = ( - - ) - return -} diff --git a/src/pages/knowledge-bases/create-edit/KnowledgeBasesCreateEditPage.tsx b/src/pages/knowledge-bases/create-edit/KnowledgeBasesCreateEditPage.tsx deleted file mode 100644 index 15e3b77ce..000000000 --- a/src/pages/knowledge-bases/create-edit/KnowledgeBasesCreateEditPage.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import { Grid } from '@mui/material' -import { TextField } from 'components/forms/TextField' -import { Autocomplete } from 'components/forms/Autocomplete' -import { LandingHeader } from 'components/LandingHeader' -import PaperLayout from 'layouts/Paper' -import React, { useEffect } from 'react' -import { FormProvider, Resolver, useForm } from 'react-hook-form' -import { yupResolver } from '@hookform/resolvers/yup' -import { Redirect, RouteComponentProps } from 'react-router-dom' -import { isEqual } from 'lodash' -import { - CreateAplKnowledgeBaseApiArg, - useCreateAplKnowledgeBaseMutation, - useDeleteAplKnowledgeBaseMutation, - useEditAplKnowledgeBaseMutation, - useGetAiModelsQuery, - useGetAplKnowledgeBaseQuery, -} from 'redux/otomiApi' -import { useTranslation } from 'react-i18next' -import FormRow from 'components/forms/FormRow' -import { useAppSelector } from 'redux/hooks' -import Section from 'components/Section' -import DeleteButton from 'components/DeleteButton' -import { LoadingButton } from '@mui/lab' -import { Divider } from 'components/Divider' -import { knowledgeBaseSchema } from './create-edit-knowledgeBases.validator' - -interface Params { - teamId: string - knowledgeBaseName?: string -} - -export default function KnowledgeBasesCreateEditPage({ - match: { - params: { teamId, knowledgeBaseName }, - }, -}: RouteComponentProps): React.ReactElement { - const { t } = useTranslation() - - const [create, { isLoading: isLoadingCreate, isSuccess: isSuccessCreate }] = useCreateAplKnowledgeBaseMutation() - const [update, { isLoading: isLoadingUpdate, isSuccess: isSuccessUpdate }] = useEditAplKnowledgeBaseMutation() - const [del, { isLoading: isLoadingDelete, isSuccess: isSuccessDelete }] = useDeleteAplKnowledgeBaseMutation() - const { data, isLoading, isFetching, isError, refetch } = useGetAplKnowledgeBaseQuery( - { teamId, knowledgeBaseName }, - { skip: !knowledgeBaseName }, - ) - const { data: aiModels } = useGetAiModelsQuery() - - const isDirty = useAppSelector(({ global: { isDirty } }) => isDirty) - useEffect(() => { - if (isDirty !== false) return - if (!isFetching) refetch() - }, [isDirty]) - - type FormType = CreateAplKnowledgeBaseApiArg['body'] - - const defaultValues: FormType = { - kind: 'AkamaiKnowledgeBase' as const, - metadata: { - name: '', - }, - spec: { - sourceUrl: '', - modelName: '', - }, - } - - const methods = useForm({ - resolver: yupResolver(knowledgeBaseSchema) as unknown as Resolver, - defaultValues, - }) - - const { - register, - reset, - handleSubmit, - watch, - formState: { errors }, - setValue, - } = methods - - useEffect(() => { - if (data) reset(data) - }, [data, reset]) - - const onSubmit = (formData: FormType) => { - const body = { ...formData } - - if (knowledgeBaseName) update({ teamId, knowledgeBaseName, body }) - else create({ teamId, body }) - } - - const mutating = isLoadingCreate || isLoadingUpdate || isLoadingDelete - if (!mutating && (isSuccessCreate || isSuccessUpdate || isSuccessDelete)) - return - - const loading = isLoading - - if (loading) return - - return ( - - - - -
-
- - { - const value = e.target.value - setValue('metadata.name', value) - }} - error={!!errors.metadata?.name} - helperText={errors.metadata?.name?.message?.toString()} - disabled={!!knowledgeBaseName} - /> - - - - - - { - const value = e.target.value - setValue('spec.sourceUrl', value) - }} - error={!!errors.spec?.sourceUrl} - helperText={errors.spec?.sourceUrl?.message?.toString()} - value={watch('spec.sourceUrl') || ''} - /> - - - - - - model.spec.modelType === 'embedding') - .map((model) => model.metadata.name) || [] - } - getOptionLabel={(option) => { - const model = aiModels?.find((m) => m.metadata.name === option) - return model?.spec.displayName || option - }} - value={watch('spec.modelName') || null} - onChange={(_, value) => { - setValue('spec.modelName', value || '') - }} - errorText={errors.spec?.modelName?.message?.toString()} - helperText={errors.spec?.modelName?.message?.toString()} - /> - -
- - {knowledgeBaseName && ( - del({ teamId, knowledgeBaseName })} - resourceName={watch('metadata.name')} - resourceType='knowledgebase' - data-cy='button-delete-knowledgebase' - sx={{ float: 'right', textTransform: 'capitalize', ml: 2 }} - loading={isLoadingDelete} - disabled={isLoadingDelete || isLoadingCreate || isLoadingUpdate} - /> - )} - - {knowledgeBaseName ? 'Save Changes' : 'Create Knowledge Base'} - - -
-
-
- ) -} diff --git a/src/pages/knowledge-bases/create-edit/create-edit-knowledgeBases.validator.ts b/src/pages/knowledge-bases/create-edit/create-edit-knowledgeBases.validator.ts deleted file mode 100644 index 6d429cf90..000000000 --- a/src/pages/knowledge-bases/create-edit/create-edit-knowledgeBases.validator.ts +++ /dev/null @@ -1,24 +0,0 @@ -import * as yup from 'yup' - -// Schema for Knowledge Base form validation -export const knowledgeBaseSchema = yup.object({ - kind: yup.string().oneOf(['AkamaiKnowledgeBase']).required(), - metadata: yup.object({ - name: yup - .string() - .required('Knowledge base name is required') - .min(2, 'Knowledge base name must be at least 2 characters') - .matches( - /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/, - 'Name must start and end with a lowercase letter or number, and can only contain lowercase letters, numbers, and hyphens', - ), - }), - spec: yup.object({ - sourceUrl: yup - .string() - .required('Data source URL is required') - .url('Please enter a valid URL (e.g., https://example.com/vector-db.zip)') - .matches(/^https?:\/\//, 'Data source must be a valid HTTP or HTTPS URL'), - modelName: yup.string().required('Please select an embedding model'), - }), -}) diff --git a/src/pages/knowledge-bases/index.tsx b/src/pages/knowledge-bases/index.tsx deleted file mode 100644 index 78bc814aa..000000000 --- a/src/pages/knowledge-bases/index.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import KnowledgeBasesOverviewPage from './overview/KnowledgeBasesOverviewPage' -import KnowledgeBasesCreateEditPage from './create-edit/KnowledgeBasesCreateEditPage' - -export default { - KnowledgeBasesOverviewPage, - KnowledgeBasesCreateEditPage, -} diff --git a/src/pages/knowledge-bases/overview/KnowledgeBasesOverviewPage.tsx b/src/pages/knowledge-bases/overview/KnowledgeBasesOverviewPage.tsx deleted file mode 100644 index 9ec4e3d45..000000000 --- a/src/pages/knowledge-bases/overview/KnowledgeBasesOverviewPage.tsx +++ /dev/null @@ -1,93 +0,0 @@ -import PaperLayout from 'layouts/Paper' -import React, { useEffect } from 'react' -import { useTranslation } from 'react-i18next' -import { RouteComponentProps } from 'react-router-dom' -import { getRole } from 'utils/data' -import { useGetAplKnowledgeBasesQuery } from 'redux/otomiApi' -import { useAppSelector } from 'redux/hooks' -import { HeadCell } from '../../../components/EnhancedTable' -import RLink from '../../../components/Link' -import ListTable from '../../../components/ListTable' - -const getKnowledgeBaseName = (): CallableFunction => - function (row: any): string | React.ReactElement { - const { teamId, name }: { teamId: string; name: string } = row - const path = `/teams/${teamId}/knowledge-bases/${encodeURIComponent(name)}` - return ( - - {name} - - ) - } - -const getStatus = (): CallableFunction => - function (row: any): string { - const { status } = row - return status?.phase || 'Unknown' - } - -const getEmbeddingModel = (): CallableFunction => - function (row: any): string { - const { modelName } = row - return modelName || 'N/A' - } - -interface Params { - teamId: string -} - -export default function KnowledgeBasesOverviewPage({ - match: { - params: { teamId }, - }, -}: RouteComponentProps): React.ReactElement { - const { t } = useTranslation() - - const { data: knowledgeBases, isLoading, isFetching, refetch } = useGetAplKnowledgeBasesQuery({ teamId }) - - const isDirty = useAppSelector(({ global: { isDirty } }) => isDirty) - useEffect(() => { - if (isDirty !== false) return - if (!isFetching) refetch() - }, [isDirty]) - - // Transform API response to match table format - const transformedData = - knowledgeBases?.map((kb) => ({ - name: kb.metadata.name, - teamId, - status: kb.status, - modelName: kb.spec.modelName, - })) || [] - - const headCells: HeadCell[] = [ - { - id: 'name', - label: t('Name'), - renderer: getKnowledgeBaseName(), - }, - { - id: 'status', - label: t('Status'), - renderer: getStatus(), - }, - { - id: 'embeddingModel', - label: t('Embedding Model'), - renderer: getEmbeddingModel(), - }, - ] - - const customButtonText = () => Create Knowledge Base - - const comp = ( - - ) - return -} diff --git a/src/redux/otomiApi.ts b/src/redux/otomiApi.ts index 2e1d870f1..fa349a2ed 100644 --- a/src/redux/otomiApi.ts +++ b/src/redux/otomiApi.ts @@ -492,50 +492,6 @@ const injectedRtkApi = api.injectEndpoints({ body: queryArg.body, }), }), - getAiModels: build.query({ - query: () => ({ url: `/alpha/ai/models` }), - }), - getAplKnowledgeBases: build.query({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/kb` }), - }), - createAplKnowledgeBase: build.mutation({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/kb`, method: 'POST', body: queryArg.body }), - }), - getAplKnowledgeBase: build.query({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/kb/${queryArg.knowledgeBaseName}` }), - }), - editAplKnowledgeBase: build.mutation({ - query: (queryArg) => ({ - url: `/alpha/teams/${queryArg.teamId}/kb/${queryArg.knowledgeBaseName}`, - method: 'PUT', - body: queryArg.body, - }), - }), - deleteAplKnowledgeBase: build.mutation({ - query: (queryArg) => ({ - url: `/alpha/teams/${queryArg.teamId}/kb/${queryArg.knowledgeBaseName}`, - method: 'DELETE', - }), - }), - getAplAgents: build.query({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/agents` }), - }), - createAplAgent: build.mutation({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/agents`, method: 'POST', body: queryArg.body }), - }), - getAplAgent: build.query({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/agents/${queryArg.agentName}` }), - }), - editAplAgent: build.mutation({ - query: (queryArg) => ({ - url: `/alpha/teams/${queryArg.teamId}/agents/${queryArg.agentName}`, - method: 'PUT', - body: queryArg.body, - }), - }), - deleteAplAgent: build.mutation({ - query: (queryArg) => ({ url: `/alpha/teams/${queryArg.teamId}/agents/${queryArg.agentName}`, method: 'DELETE' }), - }), }), overrideExisting: false, }) @@ -2035,24 +1991,28 @@ export type DeleteAplServiceApiArg = { export type GetAllSealedSecretsApiResponse = /** status 200 Successfully obtained all sealed secrets */ { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } }[] @@ -2069,24 +2029,28 @@ export type GetSecretsFromK8SApiArg = { export type GetTeamSealedSecretsApiResponse = /** status 200 Successfully obtained sealed secrets */ { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } }[] @@ -2097,24 +2061,28 @@ export type GetTeamSealedSecretsApiArg = { export type CreateSealedSecretApiResponse = /** status 200 Successfully stored sealed secret configuration */ { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } } @@ -2125,24 +2093,28 @@ export type CreateSealedSecretApiArg = { body: { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } } @@ -2150,24 +2122,28 @@ export type CreateSealedSecretApiArg = { export type GetSealedSecretApiResponse = /** status 200 Successfully obtained sealed secret configuration */ { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } } @@ -2180,24 +2156,28 @@ export type GetSealedSecretApiArg = { export type EditSealedSecretApiResponse = /** status 200 Successfully edited a team sealed secret */ { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } } @@ -2210,24 +2190,28 @@ export type EditSealedSecretApiArg = { body: { name: string namespace?: string - immutable?: boolean - type: - | 'kubernetes.io/opaque' - | 'kubernetes.io/dockercfg' - | 'kubernetes.io/dockerconfigjson' - | 'kubernetes.io/basic-auth' - | 'kubernetes.io/ssh-auth' - | 'kubernetes.io/tls' encryptedData: { - additionalProperties?: string + [key: string]: string } - metadata?: { - annotations?: { - additionalProperties?: string - } - finalizers?: string[] - labels?: { - additionalProperties?: string + template?: { + type?: + | 'kubernetes.io/opaque' + | 'kubernetes.io/dockercfg' + | 'kubernetes.io/dockerconfigjson' + | 'kubernetes.io/basic-auth' + | 'kubernetes.io/ssh-auth' + | 'kubernetes.io/tls' + immutable?: boolean + metadata?: { + name?: string + namespace?: string + annotations?: { + [key: string]: string + } + labels?: { + [key: string]: string + } + finalizers?: string[] } } } @@ -5692,9 +5676,6 @@ export type GetSettingsApiResponse = /** status 200 The request is successful. * | { type?: 'disabled' } - | { - type?: 'minioLocal' - } | { linode: { region: string @@ -5955,9 +5936,6 @@ export type EditSettingsApiArg = { | { type?: 'disabled' } - | { - type?: 'minioLocal' - } | { linode: { region: string @@ -6201,355 +6179,6 @@ export type EditAppApiArg = { } } } -export type GetAiModelsApiResponse = /** status 200 Successfully obtained shared AI models */ ({ - kind: 'AplAIModel' - spec: { - displayName?: string - modelEndpoint: string - modelType: 'foundation' | 'embedding' - modelDimension?: number - } -} & { - metadata: { - name: string - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -})[] -export type GetAiModelsApiArg = void -export type GetAplKnowledgeBasesApiResponse = /** status 200 Successfully obtained knowledge bases */ ({ - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -})[] -export type GetAplKnowledgeBasesApiArg = { - /** ID of team */ - teamId: string -} -export type CreateAplKnowledgeBaseApiResponse = /** status 200 Successfully stored knowledge base configuration */ { - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -} -export type CreateAplKnowledgeBaseApiArg = { - /** ID of team */ - teamId: string - /** KnowledgeBase object */ - body: { - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } - } & { - metadata: { - name: string - } - } -} -export type GetAplKnowledgeBaseApiResponse = /** status 200 Successfully obtained knowledge base configuration */ { - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } -} & { - metadata: { - name: string - } -} -export type GetAplKnowledgeBaseApiArg = { - /** ID of team */ - teamId: string - /** Name of the knowledge base */ - knowledgeBaseName: string -} -export type EditAplKnowledgeBaseApiResponse = /** status 200 Successfully edited a team knowledge base */ { - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -} -export type EditAplKnowledgeBaseApiArg = { - /** ID of team */ - teamId: string - /** Name of the knowledge base */ - knowledgeBaseName: string - /** KnowledgeBase object that contains updated values */ - body: { - kind: 'AkamaiKnowledgeBase' - spec: { - modelName: string - sourceUrl: string - } - } & { - metadata: { - name: string - } - } -} -export type DeleteAplKnowledgeBaseApiResponse = /** status 200 Successfully deleted a team knowledge base */ undefined -export type DeleteAplKnowledgeBaseApiArg = { - /** ID of team */ - teamId: string - /** Name of the knowledge base */ - knowledgeBaseName: string -} -export type GetAplAgentsApiResponse = /** status 200 Successfully obtained agents */ ({ - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -})[] -export type GetAplAgentsApiArg = { - /** ID of team */ - teamId: string -} -export type CreateAplAgentApiResponse = /** status 200 Successfully stored agent configuration */ { - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -} -export type CreateAplAgentApiArg = { - /** ID of team */ - teamId: string - /** Agent object */ - body: { - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } - } & { - metadata: { - name: string - } - } -} -export type GetAplAgentApiResponse = /** status 200 Successfully obtained agent configuration */ { - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -} -export type GetAplAgentApiArg = { - /** ID of team */ - teamId: string - /** Name of the agent */ - agentName: string -} -export type EditAplAgentApiResponse = /** status 200 Successfully edited a team agent */ { - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } -} & { - metadata: { - name: string - labels: { - 'apl.io/teamId': string - } - } -} & { - status: { - conditions?: { - lastTransitionTime?: string - message?: string - reason?: string - status?: boolean - type?: string - }[] - phase?: string - } -} -export type EditAplAgentApiArg = { - /** ID of team */ - teamId: string - /** Name of the agent */ - agentName: string - /** Agent object that contains updated values */ - body: { - kind: 'AkamaiAgent' - spec: { - foundationModel: string - agentInstructions: string - tools?: { - type: string - name: string - description?: string - endpoint?: string - }[] - } - } & { - metadata: { - name: string - } - } -} -export type DeleteAplAgentApiResponse = /** status 200 Successfully deleted a team agent */ undefined -export type DeleteAplAgentApiArg = { - /** ID of team */ - teamId: string - /** Name of the agent */ - agentName: string -} export const { useGetValuesQuery, useGetTeamsQuery, @@ -6681,15 +6310,4 @@ export const { useToggleAppsMutation, useGetTeamAppQuery, useEditAppMutation, - useGetAiModelsQuery, - useGetAplKnowledgeBasesQuery, - useCreateAplKnowledgeBaseMutation, - useGetAplKnowledgeBaseQuery, - useEditAplKnowledgeBaseMutation, - useDeleteAplKnowledgeBaseMutation, - useGetAplAgentsQuery, - useCreateAplAgentMutation, - useGetAplAgentQuery, - useEditAplAgentMutation, - useDeleteAplAgentMutation, } = injectedRtkApi diff --git a/src/setupProxy.js b/src/setupProxy.js index bf3d43122..aa8f95ec3 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -9,11 +9,6 @@ module.exports = function (app) { logLevel: 'debug', pathRewrite: { '^/api/ws': '/ws' }, }), - proxy('/agent', { - target: 'http://localhost:9099', - pathRewrite: { '^/agent': '' }, - changeOrigin: true, - }), proxy('/api', { target: 'http://localhost:8080', pathRewrite: { '^/api/': '/' },