Enabled edits for agent configurations

This commit is contained in:
Viswamedha Nalabotu 2026-02-27 14:56:20 +00:00
parent 1bb6075332
commit 700c7df542
2 changed files with 177 additions and 8 deletions

View file

@ -12,6 +12,7 @@ import {
message,
Tag,
InputNumber,
Select,
} from 'ant-design-vue'
import { marked } from 'marked'
import DOMPurify from 'dompurify'
@ -22,18 +23,32 @@ import type { AgentConfig, AgentRunResult } from '../types/agent'
const route = useRoute()
const agentStore = useAgentStore()
const agentId = route.params.id as string
const agentUuid = route.params.agentUuid as string
const agent = ref<AgentConfig>({
id: agentId,
name: 'Loading...',
description: '',
status: 'idle',
uuid: agentId,
uuid: agentUuid,
agent_type: 'knowledge',
llm_config: {},
organization: '',
})
const saveLoading = ref(false)
const editingConfig = ref(false)
const agentForm = ref({
name: '',
agent_type: 'knowledge',
model_id: '',
system_prompt: '',
})
const agentTypeOptions = [
{ label: 'Curriculum Agent', value: 'curriculum' },
{ label: 'Knowledge Agent', value: 'knowledge' },
{ label: 'Assessment Agent', value: 'assessment' },
{ label: 'Progress Monitor', value: 'monitor' },
]
const maxTokens = ref<number>(256)
const queryInput = ref('')
@ -63,8 +78,14 @@ const statusColor = (status: string) => {
const fetchAgent = async () => {
try {
const response = await apiClient.get<AgentConfig>(API.agents.configs.byId(agentId))
const response = await apiClient.get<AgentConfig>(API.agents.configs.byId(agentUuid))
agent.value = response.data
agentForm.value = {
name: response.data.name || '',
agent_type: response.data.agent_type || 'knowledge',
model_id: String(response.data.llm_config?.model_id || ''),
system_prompt: String(response.data.system_prompt || ''),
}
} catch (error) {
console.error('Failed to fetch agent:', error)
if (isAxiosError(error)) {
@ -78,6 +99,50 @@ const fetchAgent = async () => {
}
}
const resetForm = () => {
agentForm.value = {
name: agent.value.name || '',
agent_type: agent.value.agent_type || 'knowledge',
model_id: String(agent.value.llm_config?.model_id || ''),
system_prompt: String(agent.value.system_prompt || ''),
}
editingConfig.value = false
}
const saveConfig = async () => {
const payload = {
name: agentForm.value.name.trim(),
system_prompt: agentForm.value.system_prompt.trim(),
}
if (!payload.name) {
message.error('Agent name is required')
return
}
if (!payload.system_prompt) {
message.error('System prompt is required')
return
}
saveLoading.value = true
try {
const response = await apiClient.patch<AgentConfig>(API.agents.configs.byId(agentUuid), payload)
agent.value = response.data
editingConfig.value = false
message.success('Agent configuration updated')
} catch (error) {
console.error('Failed to update agent config:', error)
if (isAxiosError(error)) {
message.error(error.response?.data?.detail || 'Failed to update configuration')
} else {
message.error('Failed to update configuration')
}
} finally {
saveLoading.value = false
}
}
const renderedAgentResponse = computed(() => {
const rawMarkdown = agentResponse.value
if (!rawMarkdown) return ''
@ -110,7 +175,7 @@ const stopAgent = () => {
onMounted(() => {
fetchAgent()
agentStore.connect(agentId)
agentStore.connect(agentUuid)
})
onUnmounted(() => {
@ -132,6 +197,52 @@ onUnmounted(() => {
{{ agent.description || 'No description available' }}
</Typography.Paragraph>
<Typography.Title :level="4" class="section-title">Configuration</Typography.Title>
<div class="execution-controls">
<Space direction="vertical" style="width: 100%" :size="12">
<div>
<Typography.Text>Agent Name:</Typography.Text>
<Input v-model:value="agentForm.name" :disabled="!editingConfig" />
</div>
<div>
<Typography.Text>Agent Type:</Typography.Text>
<Select
v-model:value="agentForm.agent_type"
:options="agentTypeOptions"
disabled
style="width: 100%"
/>
</div>
<div>
<Typography.Text>Model ID:</Typography.Text>
<Input v-model:value="agentForm.model_id" disabled />
</div>
<div>
<Typography.Text>System Prompt:</Typography.Text>
<Input.TextArea
v-model:value="agentForm.system_prompt"
:rows="6"
:disabled="!editingConfig"
/>
</div>
<Space>
<Button v-if="!editingConfig" type="primary" @click="editingConfig = true">
Edit Configuration
</Button>
<template v-else>
<Button type="primary" :loading="saveLoading" @click="saveConfig">
Save Changes
</Button>
<Button @click="resetForm">Cancel</Button>
</template>
</Space>
</Space>
</div>
<div class="connection-status">
<span>WebSocket Status:</span>
<Tag :color="agentStore.isConnected ? 'green' : 'red'">

View file

@ -1,6 +1,6 @@
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { List, Typography, Button, Card, Spin, message, Tag, Space } from 'ant-design-vue'
import { ref, onMounted, computed } from 'vue'
import { List, Typography, Button, Card, Spin, message, Tag, Space, Select } from 'ant-design-vue'
import { apiClient, API } from '../router/api'
import type { MaybePaginated } from '../types/common'
import type { AgentConfig } from '../types/agent'
@ -8,6 +8,8 @@ import type { AgentConfig } from '../types/agent'
const agents = ref<AgentConfig[]>([])
const loading = ref(false)
const loadError = ref(false)
const selectedRole = ref<string | undefined>(undefined)
const selectedAgentType = ref<string | undefined>(undefined)
const fetchAgents = async () => {
loading.value = true
@ -36,6 +38,32 @@ const getAgentTypeLabel = (type: string) => {
return types[type] || type
}
const getRoleLabel = (agent: AgentConfig) => {
const knownSuffixes = ['Curriculum Agent', 'Knowledge Agent', 'Assessment Agent', 'Progress Monitor']
const name = (agent.name || '').trim()
const suffix = knownSuffixes.find((value) => name.endsWith(value))
if (!suffix) return name
return name.slice(0, name.length - suffix.length).trim()
}
const roleOptions = computed(() => {
const values = Array.from(new Set(agents.value.map((agent) => getRoleLabel(agent)).filter(Boolean)))
return values.map((value) => ({ label: value, value }))
})
const agentTypeOptions = computed(() => {
const values = Array.from(new Set(agents.value.map((agent) => agent.agent_type).filter(Boolean)))
return values.map((value) => ({ label: getAgentTypeLabel(value), value }))
})
const filteredAgents = computed(() =>
agents.value.filter((agent) => {
const roleMatches = !selectedRole.value || getRoleLabel(agent) === selectedRole.value
const typeMatches = !selectedAgentType.value || agent.agent_type === selectedAgentType.value
return roleMatches && typeMatches
}),
)
onMounted(() => {
fetchAgents()
})
@ -49,6 +77,23 @@ onMounted(() => {
</Typography.Paragraph>
<Card class="panel" :bordered="false">
<div class="filters">
<Select
v-model:value="selectedRole"
allow-clear
placeholder="Filter by role"
:options="roleOptions"
style="min-width: 240px"
/>
<Select
v-model:value="selectedAgentType"
allow-clear
placeholder="Filter by agent type"
:options="agentTypeOptions"
style="min-width: 240px"
/>
</div>
<Spin :spinning="loading" tip="Loading Agents...">
<div v-if="loadError" class="empty">
<Typography.Paragraph type="danger">
@ -62,12 +107,19 @@ onMounted(() => {
</Typography.Paragraph>
</div>
<List v-else :data-source="agents" item-layout="horizontal">
<div v-else-if="!loading && filteredAgents.length === 0" class="empty">
<Typography.Paragraph type="secondary">
No agents match the selected filters.
</Typography.Paragraph>
</div>
<List v-else :data-source="filteredAgents" item-layout="horizontal">
<template #renderItem="{ item }">
<List.Item class="item">
<List.Item.Meta :title="item.name">
<template #description>
<Space direction="vertical">
<Tag color="geekblue">{{ getRoleLabel(item) }}</Tag>
<Tag color="blue">
{{ getAgentTypeLabel(item.agent_type) }}
</Tag>
@ -98,6 +150,12 @@ onMounted(() => {
background: #0f172a;
border: 1px solid #1f2937;
}
.filters {
display: flex;
gap: 0.75rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.item :deep(.ant-list-item-meta-title) {
color: #f8fafc;
font-weight: 600;