Added clarity to agents, fixed pinia store reset, modified chunk name paths, fixed invite page and routing
This commit is contained in:
parent
7bad133150
commit
fd9bc9db18
9 changed files with 59 additions and 49 deletions
|
|
@ -124,9 +124,9 @@ export const API = {
|
||||||
byId: (uuid: string) => `training-file/${uuid}/`,
|
byId: (uuid: string) => `training-file/${uuid}/`,
|
||||||
retry: (uuid: string) => `training-file/${uuid}/retry/`,
|
retry: (uuid: string) => `training-file/${uuid}/retry/`,
|
||||||
},
|
},
|
||||||
roleRagDocuments: {
|
knowledgeChunks: {
|
||||||
list: () => 'role-rag-document/',
|
list: () => 'knowledge-chunk/',
|
||||||
byId: (uuid: string) => `role-rag-document/${uuid}/`,
|
byId: (uuid: string) => `knowledge-chunk/${uuid}/`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const router = createRouter({
|
||||||
path: '/invite/:inviteUuid',
|
path: '/invite/:inviteUuid',
|
||||||
name: 'invite-accept',
|
name: 'invite-accept',
|
||||||
component: () => import('../views/InviteAccept.vue'),
|
component: () => import('../views/InviteAccept.vue'),
|
||||||
meta: { requiresAuth: true },
|
meta: { requiresAuth: true, authRedirect: '/register' },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '/agents',
|
path: '/agents',
|
||||||
|
|
@ -103,7 +103,8 @@ router.beforeEach((to, from, next) => {
|
||||||
return next({ path: '/' })
|
return next({ path: '/' })
|
||||||
}
|
}
|
||||||
if (to.meta?.requiresAuth && !isAuthenticated) {
|
if (to.meta?.requiresAuth && !isAuthenticated) {
|
||||||
return next({ path: '/login', query: { redirect: to.fullPath } })
|
const authPath = (to.meta?.authRedirect as string) || '/login'
|
||||||
|
return next({ path: authPath, query: { redirect: to.fullPath } })
|
||||||
}
|
}
|
||||||
if (to.meta?.requiresManager && !isManager) {
|
if (to.meta?.requiresManager && !isManager) {
|
||||||
return next({ path: '/' })
|
return next({ path: '/' })
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,9 @@ export const useAgentStore = defineStore('agent', () => {
|
||||||
clearReconnectTimer()
|
clearReconnectTimer()
|
||||||
reconnectAttempts = 0
|
reconnectAttempts = 0
|
||||||
streamBuffer.value = ''
|
streamBuffer.value = ''
|
||||||
|
eventLog.value = []
|
||||||
|
executionStatus.value = 'idle'
|
||||||
|
lastExecutionId.value = null
|
||||||
|
|
||||||
if (socket.value) {
|
if (socket.value) {
|
||||||
socket.value.close()
|
socket.value.close()
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,10 @@ export const useOnboardingAgentStore = defineStore('onboarding-agent', () => {
|
||||||
intentionalClose = false
|
intentionalClose = false
|
||||||
clearReconnectTimer()
|
clearReconnectTimer()
|
||||||
reconnectAttempts = 0
|
reconnectAttempts = 0
|
||||||
|
eventLog.value = []
|
||||||
|
executionStatus.value = 'idle'
|
||||||
|
lastExecutionId.value = null
|
||||||
|
currentPhase.value = null
|
||||||
|
|
||||||
if (socket.value) {
|
if (socket.value) {
|
||||||
socket.value.close()
|
socket.value.close()
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
import { ref, onMounted, onUnmounted, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import {
|
import {
|
||||||
|
Alert,
|
||||||
Card,
|
Card,
|
||||||
Typography,
|
Typography,
|
||||||
Button,
|
Button,
|
||||||
|
|
@ -48,6 +49,13 @@ const agentTypeOptions = [
|
||||||
{ label: 'Assessment Agent', value: 'assessment' },
|
{ label: 'Assessment Agent', value: 'assessment' },
|
||||||
{ label: 'Progress Monitor', value: 'monitor' },
|
{ label: 'Progress Monitor', value: 'monitor' },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const agentTypeDescriptions: Record<string, string> = {
|
||||||
|
curriculum: 'Guides new hires through a structured onboarding path — presenting content, tasks, and milestones in a defined sequence for a given role.',
|
||||||
|
knowledge: 'Answers ad-hoc questions by searching your uploaded training documents and knowledge base. Use this for open-ended Q&A during onboarding.',
|
||||||
|
assessment: 'Tests understanding through role-specific questions and scenarios, then reports results back to the onboarding session so progress can be tracked.',
|
||||||
|
monitor: 'Tracks overall session progress and surfaces completions or blockers for manager review without directly interacting with the new hire.',
|
||||||
|
}
|
||||||
const maxTokens = ref<number>(256)
|
const maxTokens = ref<number>(256)
|
||||||
|
|
||||||
const queryInput = ref('')
|
const queryInput = ref('')
|
||||||
|
|
@ -202,6 +210,13 @@ onUnmounted(() => {
|
||||||
disabled
|
disabled
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
|
<Alert
|
||||||
|
v-if="agentTypeDescriptions[agentForm.agent_type]"
|
||||||
|
:message="agentTypeDescriptions[agentForm.agent_type]"
|
||||||
|
type="info"
|
||||||
|
show-icon
|
||||||
|
style="margin-top: 6px"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import { List, Typography, Button, Card, Spin, message, Tag, Space, Select } from 'ant-design-vue'
|
import { List, Typography, Button, Card, Spin, message, Tag, Space, Select, Tooltip } from 'ant-design-vue'
|
||||||
import { apiClient, API } from '../router/api'
|
import { apiClient, API } from '../router/api'
|
||||||
import type { MaybePaginated } from '../types/common'
|
import type { MaybePaginated } from '../types/common'
|
||||||
import type { AgentConfig } from '../types/agent'
|
import type { AgentConfig } from '../types/agent'
|
||||||
|
|
@ -28,6 +28,13 @@ const fetchAgents = async () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const agentTypeDescriptions: Record<string, string> = {
|
||||||
|
curriculum: 'Guides new hires through a structured onboarding path in sequence.',
|
||||||
|
knowledge: 'Answers ad-hoc questions by searching uploaded training documents.',
|
||||||
|
assessment: 'Tests understanding through role-specific questions and reports results.',
|
||||||
|
monitor: 'Tracks session progress and surfaces completions or blockers.',
|
||||||
|
}
|
||||||
|
|
||||||
const getAgentTypeLabel = (type: string) => {
|
const getAgentTypeLabel = (type: string) => {
|
||||||
const types: Record<string, string> = {
|
const types: Record<string, string> = {
|
||||||
curriculum: 'Curriculum Agent',
|
curriculum: 'Curriculum Agent',
|
||||||
|
|
@ -120,9 +127,11 @@ onMounted(() => {
|
||||||
<template #description>
|
<template #description>
|
||||||
<Space direction="vertical">
|
<Space direction="vertical">
|
||||||
<Tag color="geekblue">{{ getRoleLabel(item) }}</Tag>
|
<Tag color="geekblue">{{ getRoleLabel(item) }}</Tag>
|
||||||
|
<Tooltip :title="agentTypeDescriptions[item.agent_type]">
|
||||||
<Tag color="blue">
|
<Tag color="blue">
|
||||||
{{ getAgentTypeLabel(item.agent_type) }}
|
{{ getAgentTypeLabel(item.agent_type) }}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
</Tooltip>
|
||||||
<span class="config-summary">
|
<span class="config-summary">
|
||||||
Model: {{ item.llm_config?.model_id || 'Default' }}
|
Model: {{ item.llm_config?.model_id || 'Default' }}
|
||||||
</span>
|
</span>
|
||||||
|
|
|
||||||
|
|
@ -109,14 +109,14 @@ const logos = [
|
||||||
<Divider />
|
<Divider />
|
||||||
<Row :gutter="16">
|
<Row :gutter="16">
|
||||||
<Col v-for="stat in stats" :key="stat.title" :xs="24" :sm="8">
|
<Col v-for="stat in stats" :key="stat.title" :xs="24" :sm="8">
|
||||||
<Card :bordered="false" class="stat-card" hoverable>
|
<Card :bordered="false" class="stat-card">
|
||||||
<Statistic :title="stat.title" :value="stat.value" />
|
<Statistic :title="stat.title" :value="stat.value" />
|
||||||
</Card>
|
</Card>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Col>
|
</Col>
|
||||||
<Col :xs="24" :md="10">
|
<Col :xs="24" :md="10">
|
||||||
<Card class="hero-card" hoverable :cover="null">
|
<Card class="hero-card" :cover="null">
|
||||||
<img :src="heroImage" alt="Team collaborating" class="hero-img" />
|
<img :src="heroImage" alt="Team collaborating" class="hero-img" />
|
||||||
<div class="hero-overlay">Adaptive AI playbooks</div>
|
<div class="hero-overlay">Adaptive AI playbooks</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
@ -135,7 +135,7 @@ const logos = [
|
||||||
<Typography.Title :level="2">Everything you need to ramp faster</Typography.Title>
|
<Typography.Title :level="2">Everything you need to ramp faster</Typography.Title>
|
||||||
<Row :gutter="16">
|
<Row :gutter="16">
|
||||||
<Col v-for="feature in features" :key="feature.title" :xs="24" :md="8">
|
<Col v-for="feature in features" :key="feature.title" :xs="24" :md="8">
|
||||||
<Card hoverable class="feature-card">
|
<Card class="feature-card">
|
||||||
<feature.icon two-tone-color="#2563eb" style="font-size: 28px" />
|
<feature.icon two-tone-color="#2563eb" style="font-size: 28px" />
|
||||||
<Typography.Title :level="4">{{ feature.title }}</Typography.Title>
|
<Typography.Title :level="4">{{ feature.title }}</Typography.Title>
|
||||||
<Typography.Paragraph>{{ feature.description }}</Typography.Paragraph>
|
<Typography.Paragraph>{{ feature.description }}</Typography.Paragraph>
|
||||||
|
|
@ -149,7 +149,7 @@ const logos = [
|
||||||
<Typography.Title :level="2">Prebuilt journeys, tailored in minutes</Typography.Title>
|
<Typography.Title :level="2">Prebuilt journeys, tailored in minutes</Typography.Title>
|
||||||
<Row :gutter="16">
|
<Row :gutter="16">
|
||||||
<Col v-for="journey in journeys" :key="journey.name" :xs="24" :md="8">
|
<Col v-for="journey in journeys" :key="journey.name" :xs="24" :md="8">
|
||||||
<Card hoverable class="journey-card">
|
<Card class="journey-card">
|
||||||
<template #cover>
|
<template #cover>
|
||||||
<img :alt="journey.name" :src="journey.image" />
|
<img :alt="journey.name" :src="journey.image" />
|
||||||
</template>
|
</template>
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,18 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted } from 'vue'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { Card, Button, Spin, message, Result } from 'ant-design-vue'
|
import { Card, Spin, message, Result } from 'ant-design-vue'
|
||||||
import { apiClient, isAxiosError, API } from '../router/api'
|
import { apiClient, API } from '../router/api'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const inviteUuid = route.params.inviteUuid as string
|
const inviteUuid = route.params.inviteUuid as string
|
||||||
const loading = ref(false)
|
const accepting = ref(true)
|
||||||
const accepting = ref(false)
|
|
||||||
const accepted = ref(false)
|
const accepted = ref(false)
|
||||||
const error = ref<string | null>(null)
|
|
||||||
const joinedOrganizationUuid = ref<string | null>(null)
|
const joinedOrganizationUuid = ref<string | null>(null)
|
||||||
|
|
||||||
const acceptInvite = async () => {
|
const acceptInvite = async () => {
|
||||||
accepting.value = true
|
|
||||||
error.value = null
|
|
||||||
try {
|
try {
|
||||||
const response = await apiClient.post<{ message?: string; organization?: { uuid?: string } }>(
|
const response = await apiClient.post<{ message?: string; organization?: { uuid?: string } }>(
|
||||||
API.invites.join(inviteUuid),
|
API.invites.join(inviteUuid),
|
||||||
|
|
@ -25,19 +21,10 @@ const acceptInvite = async () => {
|
||||||
message.success(response.data?.message || 'Successfully joined organization')
|
message.success(response.data?.message || 'Successfully joined organization')
|
||||||
accepted.value = true
|
accepted.value = true
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (joinedOrganizationUuid.value) {
|
router.push(joinedOrganizationUuid.value ? `/organization/${joinedOrganizationUuid.value}` : '/')
|
||||||
router.push(`/organization/${joinedOrganizationUuid.value}`)
|
|
||||||
}
|
|
||||||
else router.push('/')
|
|
||||||
}, 1500)
|
}, 1500)
|
||||||
} catch (err) {
|
} catch {
|
||||||
console.error('Failed to accept invite:', err)
|
router.push('/')
|
||||||
if (isAxiosError(err)) {
|
|
||||||
const respErr = err.response?.data?.error || err.response?.data?.detail
|
|
||||||
error.value = respErr ? String(respErr) : 'Failed to accept invite'
|
|
||||||
} else {
|
|
||||||
error.value = 'Failed to accept invite'
|
|
||||||
}
|
|
||||||
} finally {
|
} finally {
|
||||||
accepting.value = false
|
accepting.value = false
|
||||||
}
|
}
|
||||||
|
|
@ -50,23 +37,14 @@ onMounted(() => {
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="page">
|
<div class="page">
|
||||||
<Spin :spinning="loading" tip="Loading invite...">
|
<Spin :spinning="accepting" tip="Accepting invite...">
|
||||||
<Card class="panel" :bordered="false">
|
<Card class="panel" :bordered="false">
|
||||||
<div v-if="error">
|
|
||||||
<Result status="error" :title="error">
|
|
||||||
<template #extra>
|
|
||||||
<Button type="primary" @click="router.push('/')">Go Home</Button>
|
|
||||||
</template>
|
|
||||||
</Result>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div v-else-if="accepted">
|
|
||||||
<Result
|
<Result
|
||||||
|
v-if="accepted"
|
||||||
status="success"
|
status="success"
|
||||||
title="Successfully Joined Organization"
|
title="Successfully Joined Organization"
|
||||||
sub-title="Redirecting to organization page..."
|
sub-title="Redirecting to organization page..."
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</Card>
|
</Card>
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -936,7 +936,7 @@ onMounted(async () => {
|
||||||
size="small"
|
size="small"
|
||||||
/>
|
/>
|
||||||
<Typography.Paragraph v-else type="secondary">
|
<Typography.Paragraph v-else type="secondary">
|
||||||
No training files uploaded yet.
|
No training files uploaded yet. Use the Upload Training File button to add files — you can scope them to a specific role or make them available to all roles.
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
</div>
|
</div>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue