重命名:agent - skill
This commit is contained in:
parent
dc9bb60138
commit
dfb8f31d2a
@ -58,7 +58,7 @@ jingrow/
|
||||
│ │ │ │ ├── auth.ts # 认证API
|
||||
│ │ │ │ ├── system.ts # 系统API
|
||||
│ │ │ │ ├── workspace.ts # 工作区API
|
||||
│ │ │ │ ├── agents.ts # AI代理API
|
||||
│ │ │ │ ├── skills.ts # AI代理API
|
||||
│ │ │ │ ├── nodes.ts # AI节点API
|
||||
│ │ │ │ ├── embedding.ts # 嵌入API
|
||||
│ │ │ │ ├── localJobs.ts # 本地任务API
|
||||
|
||||
@ -315,7 +315,7 @@ const breadcrumbItems = computed(() => {
|
||||
const map: Record<string, string> = {
|
||||
Dashboard: t('Dashboard'),
|
||||
AgentList: t('Agents'),
|
||||
AgentDetail: t('Agent Detail'),
|
||||
SkillDetail: t('Skill Detail'),
|
||||
NodeList: t('Node Management'),
|
||||
NodeDetail: t('Node Detail'),
|
||||
LocalJobList: t('Local Jobs'),
|
||||
|
||||
@ -177,13 +177,13 @@ const router = createRouter({
|
||||
},
|
||||
{
|
||||
path: 'skill-marketplace',
|
||||
name: 'AgentMarketplace',
|
||||
component: () => import('../../views/dev/AgentMarketplace.vue')
|
||||
name: 'SkillMarketplace',
|
||||
component: () => import('../../views/dev/SkillMarketplace.vue')
|
||||
},
|
||||
{
|
||||
path: 'skill-marketplace/:name',
|
||||
name: 'AgentDetail',
|
||||
component: () => import('../../views/dev/AgentDetail.vue')
|
||||
name: 'SkillDetail',
|
||||
component: () => import('../../views/dev/SkillDetail.vue')
|
||||
},
|
||||
{
|
||||
path: 'tool-marketplace',
|
||||
@ -225,9 +225,9 @@ const router = createRouter({
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
path: 'my-published-agents',
|
||||
name: 'MyPublishedAgents',
|
||||
component: () => import('../../views/dev/MyPublishedAgents.vue'),
|
||||
path: 'my-published-skills',
|
||||
name: 'MyPublishedSkills',
|
||||
component: () => import('../../views/dev/MyPublishedSkills.vue'),
|
||||
meta: { requiresAuth: true }
|
||||
},
|
||||
{
|
||||
|
||||
@ -42,7 +42,7 @@ import { Icon } from '@iconify/vue'
|
||||
// @ts-ignore
|
||||
import AiSkillFlowBuilder from './AiSkillFlowBuilder.vue'
|
||||
import { useFlowBuilderStore } from '@/shared/stores/flowBuilder'
|
||||
import { useSkillStore } from '@/shared/stores/agent'
|
||||
import { useSkillStore } from '@/shared/stores/skill'
|
||||
import { slugToPageType } from '@/shared/utils/slug'
|
||||
import { t } from '@/shared/i18n'
|
||||
|
||||
@ -72,7 +72,7 @@ const computedInitialValue = computed(() => {
|
||||
const flowBuilderRef = ref()
|
||||
|
||||
// Computed - 优先使用 props,fallback 到 store
|
||||
const skillId = computed(() => props.skillId || flowBuilderStore.getAgentId())
|
||||
const skillId = computed(() => props.skillId || flowBuilderStore.getSkillId())
|
||||
|
||||
// 从 URL 获取 pagetype 参数
|
||||
const pagetype = computed(() => {
|
||||
|
||||
@ -17,12 +17,12 @@ class AiSkillFlowBuilder {
|
||||
|
||||
init() {
|
||||
// 设置全局智能体信息,供执行器使用
|
||||
this.setup_global_agent_info();
|
||||
this.setup_global_skill_info();
|
||||
this.setup_app();
|
||||
this.watch_changes();
|
||||
}
|
||||
|
||||
setup_global_agent_info() {
|
||||
setup_global_skill_info() {
|
||||
// 设置全局变量,让执行器能够获取到智能体信息
|
||||
if (this.frm && this.frm.pg && this.frm.pg.name) {
|
||||
window.current_skill_name = this.frm.pg.name;
|
||||
|
||||
@ -32,37 +32,3 @@ export const updateSkillApi = async (name: string, data: Partial<AiSkill>, pageT
|
||||
throw new Error(error.message || '更新Ai Skill失败')
|
||||
}
|
||||
}
|
||||
import type { AIAgent } from '../types'
|
||||
import { getRecord, updateRecord } from './common'
|
||||
|
||||
// 重新导出类型,供其他模块使用
|
||||
export type { AIAgent }
|
||||
|
||||
export const getAgentDetail = async (name: string, pageType: string): Promise<AIAgent> => {
|
||||
try {
|
||||
const result = await getRecord(pageType, name)
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || '获取AI Agent详情失败')
|
||||
}
|
||||
|
||||
return result.data
|
||||
} catch (error: any) {
|
||||
throw new Error(error.message || '获取AI Agent详情失败')
|
||||
}
|
||||
}
|
||||
|
||||
export const updateAgentApi = async (name: string, data: Partial<AIAgent>, pageType: string): Promise<AIAgent> => {
|
||||
try {
|
||||
const result = await updateRecord(pageType, name, data)
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || '更新AI Agent失败')
|
||||
}
|
||||
|
||||
return result.data
|
||||
} catch (error: any) {
|
||||
console.error("Error in updateAgentApi:", error)
|
||||
throw new Error(error.message || '更新AI Agent失败')
|
||||
}
|
||||
}
|
||||
@ -1,90 +0,0 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getSkillDetail, updateSkillApi, type AiSkill } from '../api/agents'
|
||||
|
||||
export const useSkillStore = defineStore('skill', () => {
|
||||
const currentSkill = ref<AiSkill | null>(null)
|
||||
const currentPageType = ref<string>('')
|
||||
|
||||
// 获取单个Ai Skill
|
||||
const fetchSkill = async (name: string, pageType: string) => {
|
||||
try {
|
||||
const skillData = await getSkillDetail(name, pageType)
|
||||
currentSkill.value = skillData
|
||||
currentPageType.value = pageType
|
||||
} catch (err: any) {
|
||||
console.error('获取Ai Skill详情失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// 更新Ai Skill
|
||||
const updateSkill = async (name: string, data: Partial<AiSkill>, pageType: string) => {
|
||||
try {
|
||||
await updateSkillApi(name, data, pageType)
|
||||
// 更新成功后,手动更新本地状态
|
||||
if (currentSkill.value && currentSkill.value.name === name) {
|
||||
currentSkill.value = { ...currentSkill.value, ...data }
|
||||
}
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
console.error('更新Ai Skill失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
currentSkill,
|
||||
currentPageType,
|
||||
|
||||
// 方法
|
||||
fetchSkill,
|
||||
updateSkill
|
||||
}
|
||||
})
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getAgentDetail, updateAgentApi, type AIAgent } from '../api/agents'
|
||||
|
||||
export const useAgentStore = defineStore('agent', () => {
|
||||
const currentAgent = ref<AIAgent | null>(null)
|
||||
const currentPageType = ref<string>('')
|
||||
|
||||
// 获取单个AI Agent
|
||||
const fetchAgent = async (name: string, pageType: string) => {
|
||||
try {
|
||||
const agentData = await getAgentDetail(name, pageType)
|
||||
currentAgent.value = agentData
|
||||
currentPageType.value = pageType
|
||||
} catch (err: any) {
|
||||
console.error('获取AI Agent详情失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// 更新AI Agent
|
||||
const updateAgent = async (name: string, data: Partial<AIAgent>, pageType: string) => {
|
||||
try {
|
||||
await updateAgentApi(name, data, pageType)
|
||||
// 更新成功后,手动更新本地状态
|
||||
if (currentAgent.value && currentAgent.value.name === name) {
|
||||
currentAgent.value = { ...currentAgent.value, ...data }
|
||||
}
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
console.error('更新AI Agent失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
currentAgent,
|
||||
currentPageType,
|
||||
|
||||
// 方法
|
||||
fetchAgent,
|
||||
updateAgent
|
||||
}
|
||||
})
|
||||
@ -18,7 +18,7 @@ export const useFlowBuilderStore = defineStore('flowBuilder', () => {
|
||||
flowData.value = data
|
||||
}
|
||||
|
||||
const setAgentId = (id: string) => {
|
||||
const setSkillId = (id: string) => {
|
||||
skillId.value = id
|
||||
}
|
||||
|
||||
@ -47,7 +47,7 @@ export const useFlowBuilderStore = defineStore('flowBuilder', () => {
|
||||
return flowData.value
|
||||
}
|
||||
|
||||
const getAgentId = () => {
|
||||
const getSkillId = () => {
|
||||
return skillId.value
|
||||
}
|
||||
|
||||
@ -59,7 +59,7 @@ export const useFlowBuilderStore = defineStore('flowBuilder', () => {
|
||||
|
||||
// Actions
|
||||
setFlowData,
|
||||
setAgentId,
|
||||
setSkillId,
|
||||
activateFlowBuilder,
|
||||
deactivateFlowBuilder,
|
||||
updateFlowData,
|
||||
@ -67,6 +67,6 @@ export const useFlowBuilderStore = defineStore('flowBuilder', () => {
|
||||
// Getters
|
||||
hasFlowData,
|
||||
getFlowData,
|
||||
getAgentId
|
||||
getSkillId
|
||||
}
|
||||
})
|
||||
|
||||
45
frontend/src/shared/stores/skill.ts
Normal file
45
frontend/src/shared/stores/skill.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref } from 'vue'
|
||||
import { getSkillDetail, updateSkillApi, type AiSkill } from '../api/skills'
|
||||
|
||||
export const useSkillStore = defineStore('skill', () => {
|
||||
const currentSkill = ref<AiSkill | null>(null)
|
||||
const currentPageType = ref<string>('')
|
||||
|
||||
// 获取单个Ai Skill
|
||||
const fetchSkill = async (name: string, pageType: string) => {
|
||||
try {
|
||||
const skillData = await getSkillDetail(name, pageType)
|
||||
currentSkill.value = skillData
|
||||
currentPageType.value = pageType
|
||||
} catch (err: any) {
|
||||
console.error('获取Ai Skill详情失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
// 更新Ai Skill
|
||||
const updateSkill = async (name: string, data: Partial<AiSkill>, pageType: string) => {
|
||||
try {
|
||||
await updateSkillApi(name, data, pageType)
|
||||
// 更新成功后,手动更新本地状态
|
||||
if (currentSkill.value && currentSkill.value.name === name) {
|
||||
currentSkill.value = { ...currentSkill.value, ...data }
|
||||
}
|
||||
return { success: true }
|
||||
} catch (err: any) {
|
||||
console.error('更新Ai Skill失败:', err)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
// 状态
|
||||
currentSkill,
|
||||
currentPageType,
|
||||
|
||||
// 方法
|
||||
fetchSkill,
|
||||
updateSkill
|
||||
}
|
||||
})
|
||||
@ -1,5 +1,5 @@
|
||||
// 全局类型定义
|
||||
export * from './agent'
|
||||
export * from './skill'
|
||||
export * from './flow'
|
||||
export * from './node'
|
||||
export * from './common'
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// 智能体相关类型定义
|
||||
// 智能体(Skill)相关类型定义
|
||||
export interface AiSkill {
|
||||
name: string
|
||||
skill_name: string
|
||||
@ -9,7 +9,7 @@
|
||||
<!-- 原来的4个统计 -->
|
||||
<n-grid-item>
|
||||
<n-card>
|
||||
<n-statistic :label="t('Total Skills')" :value="stats.agents" />
|
||||
<n-statistic :label="t('Total Skills')" :value="stats.skills" />
|
||||
</n-card>
|
||||
</n-grid-item>
|
||||
<n-grid-item>
|
||||
@ -71,7 +71,7 @@ import { t } from '../shared/i18n'
|
||||
import { getCount, getLocalJobCount } from '../shared/api/common'
|
||||
|
||||
const stats = reactive({
|
||||
agents: 0,
|
||||
skills: 0,
|
||||
nodes: 0,
|
||||
taskQueue: 0,
|
||||
scheduledTasks: 0,
|
||||
@ -87,9 +87,9 @@ const loadStats = async () => {
|
||||
try {
|
||||
// 第一行:原来的4个统计
|
||||
// 获取技能总数
|
||||
const agentsResult = await getCount('Local Ai Skill')
|
||||
if (agentsResult.success) {
|
||||
stats.agents = agentsResult.count || 0
|
||||
const skillsResult = await getCount('Local Ai Skill')
|
||||
if (skillsResult.success) {
|
||||
stats.skills = skillsResult.count || 0
|
||||
}
|
||||
|
||||
// 获取节点总数
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<div class="my-published-agents">
|
||||
<div class="my-published-skills">
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="header-text">
|
||||
<h1>{{ t('My Published Agents') }}</h1>
|
||||
<p>{{ t('Manage your published agents in the marketplace') }}</p>
|
||||
<h1>{{ t('My Published Skills') }}</h1>
|
||||
<p>{{ t('Manage your published skills in the marketplace') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -14,17 +14,17 @@
|
||||
<div class="search-bar">
|
||||
<n-input
|
||||
v-model:value="searchQuery"
|
||||
:placeholder="t('Search agents...')"
|
||||
:placeholder="t('Search skills...')"
|
||||
clearable
|
||||
size="large"
|
||||
@keyup.enter="loadAgents"
|
||||
@keyup.enter="loadSkills"
|
||||
class="search-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<n-icon><Icon icon="tabler:search" /></n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button type="primary" size="large" @click="loadAgents" class="search-button">
|
||||
<n-button type="primary" size="large" @click="loadSkills" class="search-button">
|
||||
<template #icon>
|
||||
<n-icon><Icon icon="tabler:search" /></n-icon>
|
||||
</template>
|
||||
@ -33,10 +33,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agents-section" v-if="!loading && agents.length > 0">
|
||||
<!-- 排序控件 -->
|
||||
<div class="agents-header">
|
||||
<div class="agents-title">
|
||||
<div class="skills-section" v-if="!loading && skills.length > 0">
|
||||
<div class="skills-header">
|
||||
<div class="skills-title">
|
||||
</div>
|
||||
<div class="sort-controls">
|
||||
<n-select
|
||||
@ -44,59 +43,57 @@
|
||||
:options="sortOptions"
|
||||
:placeholder="t('Sort by')"
|
||||
style="width: 150px"
|
||||
@update:value="loadAgents"
|
||||
@update:value="loadSkills"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agents-grid">
|
||||
<div v-for="agent in agents" :key="agent.name" class="skill-card">
|
||||
<!-- 智能体图标 -->
|
||||
<div class="skill-icon" @click="viewAgentDetail(agent)">
|
||||
<div class="skills-grid">
|
||||
<div v-for="skill in skills" :key="skill.name" class="skill-card">
|
||||
<div class="skill-icon" @click="viewSkillDetail(skill)">
|
||||
<Icon
|
||||
v-if="agent.icon"
|
||||
:icon="agent.icon"
|
||||
v-if="skill.icon"
|
||||
:icon="skill.icon"
|
||||
:width="64"
|
||||
:height="64"
|
||||
:style="{ color: agent.color || '#6b7280' }"
|
||||
:style="{ color: skill.color || '#6b7280' }"
|
||||
/>
|
||||
<div v-else class="skill-icon-placeholder">
|
||||
<n-icon size="64"><Icon icon="hugeicons:robotic" /></n-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 智能体信息 -->
|
||||
<div class="skill-content">
|
||||
<div class="skill-header">
|
||||
<div class="skill-title-section">
|
||||
<h3 @click="viewAgentDetail(agent)" class="clickable-title">{{ agent.title || agent.skill_name || agent.name }}</h3>
|
||||
<h3 @click="viewSkillDetail(skill)" class="clickable-title">{{ skill.title || skill.skill_name || skill.name }}</h3>
|
||||
<div class="skill-meta">
|
||||
<div class="skill-team" v-if="agent.team">
|
||||
<div class="skill-team" v-if="skill.team">
|
||||
<n-icon><Icon icon="tabler:users" /></n-icon>
|
||||
<span>{{ agent.team }}</span>
|
||||
<span>{{ skill.team }}</span>
|
||||
</div>
|
||||
<span v-if="agent.status" class="status-badge" :class="getStatusClass(agent.status)">
|
||||
{{ t(agent.status) }}
|
||||
<span v-if="skill.status" class="status-badge" :class="getStatusClass(skill.status)">
|
||||
{{ t(skill.status) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="skill-name" v-if="agent.skill_name">
|
||||
{{ agent.skill_name }}
|
||||
<div class="skill-name" v-if="skill.skill_name">
|
||||
{{ skill.skill_name }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-description" v-if="agent.description">
|
||||
{{ truncateText(agent.description, 80) }}
|
||||
<div class="skill-description" v-if="skill.description">
|
||||
{{ truncateText(skill.description, 80) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-actions">
|
||||
<n-button type="default" @click="viewAgentDetail(agent)">
|
||||
<n-button type="default" @click="viewSkillDetail(skill)">
|
||||
{{ t('View Details') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
type="error"
|
||||
@click="deleteAgent(agent)"
|
||||
@click="deleteSkill(skill)"
|
||||
>
|
||||
{{ t('Delete') }}
|
||||
</n-button>
|
||||
@ -104,7 +101,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<n-pagination
|
||||
v-model:page="page"
|
||||
@ -113,7 +109,7 @@
|
||||
show-size-picker
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
@update:page="loadAgents"
|
||||
@update:page="loadSkills"
|
||||
@update:page-size="handlePageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
@ -121,12 +117,12 @@
|
||||
|
||||
<div v-if="loading" class="loading">
|
||||
<n-spin size="large">
|
||||
<template #description>{{ t('Loading agents...') }}</template>
|
||||
<template #description>{{ t('Loading skills...') }}</template>
|
||||
</n-spin>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && agents.length === 0" class="empty">
|
||||
<n-empty :description="t('No agents found')">
|
||||
<div v-if="!loading && skills.length === 0" class="empty">
|
||||
<n-empty :description="t('No skills found')">
|
||||
<template #icon>
|
||||
<n-icon><Icon icon="hugeicons:robotic" /></n-icon>
|
||||
</template>
|
||||
@ -150,13 +146,12 @@ const router = useRouter()
|
||||
|
||||
const searchQuery = ref('')
|
||||
const loading = ref(false)
|
||||
const agents = ref<any[]>([])
|
||||
const skills = ref<any[]>([])
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
|
||||
const sortBy = ref('creation desc')
|
||||
|
||||
// 排序选项
|
||||
const sortOptions = computed(() => [
|
||||
{ label: t('Latest'), value: 'creation desc' },
|
||||
{ label: t('Oldest'), value: 'creation asc' },
|
||||
@ -165,10 +160,9 @@ const sortOptions = computed(() => [
|
||||
{ label: t('Most Popular'), value: 'modified desc' }
|
||||
])
|
||||
|
||||
// 计算总页数
|
||||
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / pageSize.value)))
|
||||
|
||||
async function loadAgents() {
|
||||
async function loadSkills() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
@ -178,22 +172,20 @@ async function loadAgents() {
|
||||
sort_by: sortBy.value
|
||||
})
|
||||
|
||||
const response = await axios.get(`/jingrow/my-published-agents?${params}`)
|
||||
const response = await axios.get(`/jingrow/my-published-skills?${params}`)
|
||||
const data = response.data
|
||||
|
||||
// 如果API返回分页数据
|
||||
if (data.items) {
|
||||
agents.value = data.items
|
||||
skills.value = data.items
|
||||
total.value = data.total || 0
|
||||
} else {
|
||||
// 兼容旧API格式
|
||||
agents.value = data || []
|
||||
total.value = agents.value.length
|
||||
skills.value = data || []
|
||||
total.value = skills.value.length
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load agents:', error)
|
||||
message.error(t('Failed to load agents'))
|
||||
agents.value = []
|
||||
console.error('Failed to load skills:', error)
|
||||
message.error(t('Failed to load skills'))
|
||||
skills.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
@ -204,14 +196,13 @@ function handlePageSizeChange(newPageSize: number) {
|
||||
pageSize.value = newPageSize
|
||||
page.value = 1
|
||||
localStorage.setItem('itemsPerPage', newPageSize.toString())
|
||||
loadAgents()
|
||||
loadSkills()
|
||||
}
|
||||
|
||||
function viewAgentDetail(agent: any) {
|
||||
// 跳转到智能体详情页面,传递返回路径
|
||||
function viewSkillDetail(skill: any) {
|
||||
router.push({
|
||||
path: `/skill-marketplace/${agent.name}`,
|
||||
query: { returnTo: '/my-published-agents' }
|
||||
path: `/skill-marketplace/${skill.name}`,
|
||||
query: { returnTo: '/my-published-skills' }
|
||||
})
|
||||
}
|
||||
|
||||
@ -223,23 +214,20 @@ function truncateText(text: string, maxLength: number): string {
|
||||
|
||||
function getStatusClass(status: string): string {
|
||||
if (!status) return ''
|
||||
// 将状态转换为小写,并将空格替换为连字符
|
||||
return status.toLowerCase().replace(/\s+/g, '-')
|
||||
}
|
||||
|
||||
async function deleteAgent(agent: any) {
|
||||
// 使用记录的name字段删除
|
||||
const recordName = agent.name
|
||||
async function deleteSkill(skill: any) {
|
||||
const recordName = skill.name
|
||||
if (!recordName) {
|
||||
message.error(t('Agent name does not exist'))
|
||||
message.error(t('Skill name does not exist'))
|
||||
return
|
||||
}
|
||||
|
||||
// 显示确认对话框,显示智能体标题
|
||||
const agentTitle = agent.title || agent.skill_name || recordName
|
||||
const skillTitle = skill.title || skill.skill_name || recordName
|
||||
dialog.warning({
|
||||
title: t('Confirm Delete'),
|
||||
content: t('Are you sure you want to delete agent "{0}"? This action cannot be undone.').replace('{0}', agentTitle),
|
||||
content: t('Are you sure you want to delete skill "{0}"? This action cannot be undone.').replace('{0}', skillTitle),
|
||||
positiveText: t('Confirm Delete'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: async () => {
|
||||
@ -250,21 +238,19 @@ async function deleteAgent(agent: any) {
|
||||
|
||||
async function performDelete(skillName: string) {
|
||||
try {
|
||||
// 调用本地API,由后端转发到云端
|
||||
const response = await axios.post('/jingrow/delete-published-agent', {
|
||||
const response = await axios.post('/jingrow/delete-published-skill', {
|
||||
name: skillName
|
||||
})
|
||||
|
||||
if (response.data && response.data.success) {
|
||||
message.success(response.data.message || t('Agent deleted successfully'))
|
||||
// 刷新智能体列表
|
||||
loadAgents()
|
||||
message.success(response.data.message || t('Skill deleted successfully'))
|
||||
loadSkills()
|
||||
} else {
|
||||
const errorMsg = response.data?.message || response.data?.error || t('Delete failed')
|
||||
message.error(errorMsg)
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Delete agent error:', error)
|
||||
console.error('Delete skill error:', error)
|
||||
const errorMsg = error.response?.data?.detail ||
|
||||
error.response?.data?.message ||
|
||||
error.message ||
|
||||
@ -274,32 +260,29 @@ async function performDelete(skillName: string) {
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadAgents()
|
||||
loadSkills()
|
||||
})
|
||||
|
||||
// 监听搜索和排序变化
|
||||
watch([searchQuery, sortBy], () => {
|
||||
page.value = 1 // 重置到第一页
|
||||
loadAgents()
|
||||
page.value = 1
|
||||
loadSkills()
|
||||
}, { deep: true })
|
||||
|
||||
// 监听分页变化
|
||||
watch([page], () => {
|
||||
loadAgents()
|
||||
loadSkills()
|
||||
})
|
||||
|
||||
// 监听每页数量变化(从系统设置)
|
||||
watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
if (newValue) {
|
||||
pageSize.value = parseInt(newValue)
|
||||
page.value = 1 // 重置到第一页
|
||||
loadAgents()
|
||||
page.value = 1
|
||||
loadSkills()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.my-published-agents {
|
||||
.my-published-skills {
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
@ -332,18 +315,18 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.agents-section {
|
||||
.skills-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.agents-header {
|
||||
.skills-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
.agents-title h2 {
|
||||
.skills-title h2 {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
font-weight: 600;
|
||||
@ -404,7 +387,7 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
.skills-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 24px;
|
||||
@ -598,7 +581,6 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
min-height: 300px;
|
||||
}
|
||||
|
||||
/* 响应式设计 */
|
||||
@media (max-width: 768px) {
|
||||
.header-content {
|
||||
flex-direction: column;
|
||||
@ -625,7 +607,7 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
.skills-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
@ -639,4 +621,3 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="header-text">
|
||||
<h1>{{ agent?.title || agent?.skill_name || t('Agent Details') }}</h1>
|
||||
<h1>{{ skill?.title || skill?.skill_name || t('Skill Details') }}</h1>
|
||||
</div>
|
||||
<div class="header-actions">
|
||||
<n-button @click="goBack" size="medium">
|
||||
@ -13,16 +13,16 @@
|
||||
{{ t('Back') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
:type="isCurrentAgentInstalled ? 'warning' : 'primary'"
|
||||
@click="installAgent"
|
||||
:type="isCurrentSkillInstalled ? 'warning' : 'primary'"
|
||||
@click="installSkill"
|
||||
size="medium"
|
||||
>
|
||||
<template #icon>
|
||||
<n-icon>
|
||||
<Icon :icon="isCurrentAgentInstalled ? 'tabler:check' : 'tabler:download'" />
|
||||
<Icon :icon="isCurrentSkillInstalled ? 'tabler:check' : 'tabler:download'" />
|
||||
</n-icon>
|
||||
</template>
|
||||
{{ isCurrentAgentInstalled ? t('Installed') : t('Install') }}
|
||||
{{ isCurrentSkillInstalled ? t('Installed') : t('Install') }}
|
||||
</n-button>
|
||||
</div>
|
||||
</div>
|
||||
@ -31,7 +31,7 @@
|
||||
<div v-if="loading" class="loading-container">
|
||||
<n-spin size="large">
|
||||
<template #description>
|
||||
{{ t('Loading agent details...') }}
|
||||
{{ t('Loading skill details...') }}
|
||||
</template>
|
||||
</n-spin>
|
||||
</div>
|
||||
@ -44,21 +44,18 @@
|
||||
</n-empty>
|
||||
</div>
|
||||
|
||||
<div v-else-if="agent" class="skill-content">
|
||||
<!-- 整体卡片布局 -->
|
||||
<div v-else-if="skill" class="skill-content">
|
||||
<div class="skill-card">
|
||||
<!-- 上部分:智能体信息 -->
|
||||
<div class="skill-info-section">
|
||||
<div class="skill-content-layout">
|
||||
<!-- 左侧:智能体图标 -->
|
||||
<div class="skill-image-section">
|
||||
<div class="skill-image">
|
||||
<div v-if="agent.icon" class="skill-icon-container">
|
||||
<div v-if="skill.icon" class="skill-icon-container">
|
||||
<Icon
|
||||
:icon="agent.icon"
|
||||
:icon="skill.icon"
|
||||
:width="120"
|
||||
:height="120"
|
||||
:style="{ color: agent.color || '#6b7280' }"
|
||||
:style="{ color: skill.color || '#6b7280' }"
|
||||
/>
|
||||
</div>
|
||||
<div v-else class="placeholder-image">
|
||||
@ -67,60 +64,57 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 右侧:智能体信息 -->
|
||||
<div class="skill-info-content">
|
||||
<div class="skill-header">
|
||||
<h2 class="skill-title">{{ agent.title || agent.skill_name || t('Untitled Agent') }}</h2>
|
||||
<div v-if="agent.subtitle" class="skill-subtitle">{{ agent.subtitle }}</div>
|
||||
<h2 class="skill-title">{{ skill.title || skill.skill_name || t('Untitled Skill') }}</h2>
|
||||
<div v-if="skill.subtitle" class="skill-subtitle">{{ skill.subtitle }}</div>
|
||||
</div>
|
||||
|
||||
<div class="info-list">
|
||||
<div v-if="agent.skill_name" class="info-item">
|
||||
<span class="label">{{ t('Agent Name') }}:</span>
|
||||
<span class="value">{{ agent.skill_name }}</span>
|
||||
<div v-if="skill.skill_name" class="info-item">
|
||||
<span class="label">{{ t('Skill Name') }}:</span>
|
||||
<span class="value">{{ skill.skill_name }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="agent.status" class="info-item">
|
||||
<div v-if="skill.status" class="info-item">
|
||||
<span class="label">{{ t('Status') }}:</span>
|
||||
<span class="value">{{ agent.status }}</span>
|
||||
<span class="value">{{ skill.status }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="agent.trigger_mode" class="info-item">
|
||||
<div v-if="skill.trigger_mode" class="info-item">
|
||||
<span class="label">{{ t('Trigger Mode') }}:</span>
|
||||
<span class="value">{{ agent.trigger_mode }}</span>
|
||||
<span class="value">{{ skill.trigger_mode }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="agent.creation" class="info-item">
|
||||
<div v-if="skill.creation" class="info-item">
|
||||
<span class="label">{{ t('Created') }}:</span>
|
||||
<span class="value">{{ formatDate(agent.creation) }}</span>
|
||||
<span class="value">{{ formatDate(skill.creation) }}</span>
|
||||
</div>
|
||||
|
||||
<div v-if="agent.modified" class="info-item">
|
||||
<div v-if="skill.modified" class="info-item">
|
||||
<span class="label">{{ t('Last Updated') }}:</span>
|
||||
<span class="value">{{ formatDate(agent.modified) }}</span>
|
||||
<span class="value">{{ formatDate(skill.modified) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 下部分:描述内容 -->
|
||||
<div v-if="agent.description" class="description-section">
|
||||
<div v-if="skill.description" class="description-section">
|
||||
<h3>{{ t('Description') }}</h3>
|
||||
<div class="description-content" v-html="agent.description"></div>
|
||||
<div class="description-content" v-html="skill.description"></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 安装进度弹窗 -->
|
||||
<InstallProgressModal
|
||||
v-model="showProgressModal"
|
||||
:progress="installProgress"
|
||||
:message="installMessage"
|
||||
:status="installStatus"
|
||||
:installing="installing"
|
||||
:title="t('Installing Agent')"
|
||||
:title="t('Installing Skill')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -141,36 +135,33 @@ const dialog = useDialog()
|
||||
|
||||
const loading = ref(true)
|
||||
const error = ref('')
|
||||
const agent = ref<any>(null)
|
||||
const skill = ref<any>(null)
|
||||
|
||||
// 安装相关状态
|
||||
const installing = ref(false)
|
||||
const installProgress = ref(0)
|
||||
const installMessage = ref('')
|
||||
const installStatus = ref<'success' | 'error' | 'info'>('info')
|
||||
const showProgressModal = ref(false)
|
||||
|
||||
// 已安装智能体集合
|
||||
const installedAgentNames = ref<Set<string>>(new Set())
|
||||
const installedSkillNames = ref<Set<string>>(new Set())
|
||||
|
||||
const skillName = computed(() => route.params.name as string)
|
||||
|
||||
// 检查当前智能体是否已安装
|
||||
const isCurrentAgentInstalled = computed(() => {
|
||||
if (!agent.value) return false
|
||||
return isAgentInstalled(agent.value.skill_name || agent.value.name || '')
|
||||
const isCurrentSkillInstalled = computed(() => {
|
||||
if (!skill.value) return false
|
||||
return isSkillInstalled(skill.value.skill_name || skill.value.name || '')
|
||||
})
|
||||
|
||||
async function loadAgentDetail() {
|
||||
async function loadSkillDetail() {
|
||||
loading.value = true
|
||||
error.value = ''
|
||||
|
||||
try {
|
||||
const response = await axios.get(`/jingrow/skill-marketplace/${skillName.value}`)
|
||||
agent.value = response.data
|
||||
skill.value = response.data
|
||||
} catch (err: any) {
|
||||
console.error('Failed to load agent detail:', err)
|
||||
error.value = err.response?.data?.detail || t('Failed to load agent details')
|
||||
console.error('Failed to load skill detail:', err)
|
||||
error.value = err.response?.data?.detail || t('Failed to load skill details')
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
@ -186,39 +177,34 @@ function formatDate(dateString: string): string {
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
// 从查询参数获取返回路径
|
||||
const returnTo = route.query.returnTo as string
|
||||
if (returnTo) {
|
||||
router.push(returnTo)
|
||||
return
|
||||
}
|
||||
|
||||
// 检查路由历史
|
||||
if (window.history.length > 1) {
|
||||
router.back()
|
||||
} else {
|
||||
// 默认返回智能体市场
|
||||
router.push('/skill-marketplace')
|
||||
}
|
||||
}
|
||||
|
||||
async function installAgent() {
|
||||
if (!agent.value?.skill_flow && !agent.value?.skill_name) {
|
||||
message.error(t('Agent flow data or name is missing'))
|
||||
async function installSkill() {
|
||||
if (!skill.value?.skill_flow && !skill.value?.skill_name) {
|
||||
message.error(t('Skill flow data or name is missing'))
|
||||
return
|
||||
}
|
||||
|
||||
// 先检查智能体是否已存在
|
||||
try {
|
||||
const skillNameValue = agent.value.skill_name || agent.value.name
|
||||
const skillNameValue = skill.value.skill_name || skill.value.name
|
||||
if (skillNameValue) {
|
||||
const checkResponse = await axios.get(`/jingrow/check-agent/${skillNameValue}`)
|
||||
const checkResponse = await axios.get(`/jingrow/check-skill/${skillNameValue}`)
|
||||
|
||||
if (checkResponse.data.exists) {
|
||||
// 显示确认对话框
|
||||
dialog.warning({
|
||||
title: t('Agent already exists'),
|
||||
content: t('Agent "{0}" is already installed, do you want to overwrite?').replace('{0}', skillNameValue),
|
||||
title: t('Skill already exists'),
|
||||
content: t('Skill "{0}" is already installed, do you want to overwrite?').replace('{0}', skillNameValue),
|
||||
positiveText: t('Confirm Overwrite'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: () => {
|
||||
@ -229,7 +215,7 @@ async function installAgent() {
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Check agent exists error:', error)
|
||||
console.error('Check skill exists error:', error)
|
||||
}
|
||||
|
||||
performInstall()
|
||||
@ -243,27 +229,24 @@ async function performInstall() {
|
||||
installStatus.value = 'info'
|
||||
showProgressModal.value = true
|
||||
|
||||
// 获取流程数据和名称
|
||||
let skillFlow = agent.value.skill_flow
|
||||
let skillNameValue = agent.value.skill_name || agent.value.name
|
||||
let skillFlow = skill.value.skill_flow
|
||||
let skillNameValue = skill.value.skill_name || skill.value.name
|
||||
|
||||
if (!skillFlow) {
|
||||
throw new Error(t('Agent flow data is missing'))
|
||||
throw new Error(t('Skill flow data is missing'))
|
||||
}
|
||||
|
||||
installProgress.value = 30
|
||||
installMessage.value = t('Installing agent...')
|
||||
installMessage.value = t('Installing skill...')
|
||||
|
||||
// 如果 skill_flow 是字符串,尝试解析为 JSON
|
||||
if (typeof skillFlow === 'string') {
|
||||
try {
|
||||
skillFlow = JSON.parse(skillFlow)
|
||||
} catch (e) {
|
||||
// 如果解析失败,保持原样
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/install-agent', {
|
||||
const response = await axios.post('/jingrow/install-skill', {
|
||||
skill_name: skillNameValue,
|
||||
skill_flow: skillFlow
|
||||
}, {
|
||||
@ -272,18 +255,15 @@ async function performInstall() {
|
||||
}
|
||||
})
|
||||
|
||||
// 更新进度到安装完成
|
||||
installProgress.value = 100
|
||||
|
||||
if (response.data.success) {
|
||||
// 所有步骤完成后才显示成功
|
||||
installing.value = false
|
||||
installStatus.value = 'success'
|
||||
installMessage.value = t('Agent installed successfully!')
|
||||
message.success(t('Agent installed successfully'))
|
||||
installMessage.value = t('Skill installed successfully!')
|
||||
message.success(t('Skill installed successfully'))
|
||||
|
||||
// 刷新已安装智能体列表
|
||||
loadInstalledAgents()
|
||||
loadInstalledSkills()
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
@ -292,7 +272,7 @@ async function performInstall() {
|
||||
throw new Error(response.data.error || t('安装失败'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Install agent error:', error)
|
||||
console.error('Install skill error:', error)
|
||||
installing.value = false
|
||||
installStatus.value = 'error'
|
||||
installMessage.value = error.response?.data?.detail || error.message || t('Installation failed')
|
||||
@ -304,32 +284,29 @@ async function performInstall() {
|
||||
}
|
||||
}
|
||||
|
||||
// 加载已安装智能体列表
|
||||
async function loadInstalledAgents() {
|
||||
async function loadInstalledSkills() {
|
||||
try {
|
||||
const response = await axios.get('/jingrow/installed-skill-names')
|
||||
if (response.data.success) {
|
||||
const agents = response.data.agents || []
|
||||
installedAgentNames.value = new Set(agents.map((a: string) => a.toLowerCase()))
|
||||
const skills = response.data.skills || []
|
||||
installedSkillNames.value = new Set(skills.map((a: string) => a.toLowerCase()))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Load installed agents error:', error)
|
||||
console.error('Load installed skills error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查智能体是否已安装
|
||||
function isAgentInstalled(skillNameValue: string): boolean {
|
||||
function isSkillInstalled(skillNameValue: string): boolean {
|
||||
if (!skillNameValue) return false
|
||||
return installedAgentNames.value.has(skillNameValue.toLowerCase())
|
||||
return installedSkillNames.value.has(skillNameValue.toLowerCase())
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadAgentDetail()
|
||||
loadInstalledAgents()
|
||||
loadSkillDetail()
|
||||
loadInstalledSkills()
|
||||
|
||||
// 监听全局事件
|
||||
window.addEventListener('installedAgentsUpdated', () => {
|
||||
loadInstalledAgents()
|
||||
window.addEventListener('installedSkillsUpdated', () => {
|
||||
loadInstalledSkills()
|
||||
})
|
||||
})
|
||||
</script>
|
||||
@ -382,7 +359,6 @@ onMounted(() => {
|
||||
gap: 32px;
|
||||
}
|
||||
|
||||
/* 整体卡片布局 */
|
||||
.skill-card {
|
||||
background: white;
|
||||
border-radius: 8px;
|
||||
@ -393,8 +369,6 @@ onMounted(() => {
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
/* 上部分:智能体信息 */
|
||||
|
||||
.skill-content-layout {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 2fr;
|
||||
@ -493,7 +467,6 @@ onMounted(() => {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* 下部分:描述内容 */
|
||||
.description-section {
|
||||
padding-top: 24px;
|
||||
border-top: 1px solid #e5e7eb;
|
||||
@ -598,4 +571,3 @@ onMounted(() => {
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
<div class="page-header">
|
||||
<div class="header-content">
|
||||
<div class="header-text">
|
||||
<h1>{{ t('Agent Marketplace') }}</h1>
|
||||
<p>{{ t('Browse and install agents from Jingrow Agent Marketplace') }}</p>
|
||||
<h1>{{ t('Skill Marketplace') }}</h1>
|
||||
<p>{{ t('Browse and install skills from Jingrow Skill Marketplace') }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -14,17 +14,17 @@
|
||||
<div class="search-bar">
|
||||
<n-input
|
||||
v-model:value="searchQuery"
|
||||
:placeholder="t('Search agents...')"
|
||||
:placeholder="t('Search skills...')"
|
||||
clearable
|
||||
size="large"
|
||||
@keyup.enter="loadAgents"
|
||||
@keyup.enter="loadSkills"
|
||||
class="search-input"
|
||||
>
|
||||
<template #prefix>
|
||||
<n-icon><Icon icon="tabler:search" /></n-icon>
|
||||
</template>
|
||||
</n-input>
|
||||
<n-button type="primary" size="large" @click="loadAgents" class="search-button">
|
||||
<n-button type="primary" size="large" @click="loadSkills" class="search-button">
|
||||
<template #icon>
|
||||
<n-icon><Icon icon="tabler:search" /></n-icon>
|
||||
</template>
|
||||
@ -33,10 +33,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agents-section" v-if="!loading && agents.length > 0">
|
||||
<!-- 排序控件 -->
|
||||
<div class="agents-header">
|
||||
<div class="agents-title">
|
||||
<div class="skills-section" v-if="!loading && skills.length > 0">
|
||||
<div class="skills-header">
|
||||
<div class="skills-title">
|
||||
</div>
|
||||
<div class="sort-controls">
|
||||
<n-select
|
||||
@ -44,58 +43,56 @@
|
||||
:options="sortOptions"
|
||||
:placeholder="t('Sort by')"
|
||||
style="width: 150px"
|
||||
@update:value="loadAgents"
|
||||
@update:value="loadSkills"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="agents-grid">
|
||||
<div v-for="agent in agents" :key="agent.name" class="skill-card">
|
||||
<!-- 智能体图标 -->
|
||||
<div class="skill-icon" @click="viewAgentDetail(agent)">
|
||||
<div class="skills-grid">
|
||||
<div v-for="skill in skills" :key="skill.name" class="skill-card">
|
||||
<div class="skill-icon" @click="viewSkillDetail(skill)">
|
||||
<Icon
|
||||
v-if="agent.icon"
|
||||
:icon="agent.icon"
|
||||
v-if="skill.icon"
|
||||
:icon="skill.icon"
|
||||
:width="48"
|
||||
:height="48"
|
||||
:style="{ color: agent.color || '#6b7280' }"
|
||||
:style="{ color: skill.color || '#6b7280' }"
|
||||
/>
|
||||
<div v-else class="skill-icon-placeholder">
|
||||
<n-icon size="48"><Icon icon="hugeicons:robotic" /></n-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 智能体信息 -->
|
||||
<div class="skill-content">
|
||||
<div class="skill-header">
|
||||
<div class="skill-title-section">
|
||||
<h3 @click="viewAgentDetail(agent)" class="clickable-title">{{ agent.title || agent.skill_name || agent.name }}</h3>
|
||||
<div class="skill-name" v-if="agent.skill_name">
|
||||
{{ agent.skill_name }}
|
||||
<h3 @click="viewSkillDetail(skill)" class="clickable-title">{{ skill.title || skill.skill_name || skill.name }}</h3>
|
||||
<div class="skill-name" v-if="skill.skill_name">
|
||||
{{ skill.skill_name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-description" v-if="agent.description">
|
||||
{{ truncateText(agent.description, 80) }}
|
||||
<div class="skill-description" v-if="skill.description">
|
||||
{{ truncateText(skill.description, 80) }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="skill-actions">
|
||||
<n-button type="default" @click="viewAgentDetail(agent)">
|
||||
<n-button type="default" @click="viewSkillDetail(skill)">
|
||||
{{ t('View Details') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-if="isAgentInstalled(agent.skill_name || agent.name)"
|
||||
v-if="isSkillInstalled(skill.skill_name || skill.name)"
|
||||
type="warning"
|
||||
@click="installAgent(agent)"
|
||||
@click="installSkill(skill)"
|
||||
>
|
||||
{{ t('Installed') }}
|
||||
</n-button>
|
||||
<n-button
|
||||
v-else
|
||||
type="primary"
|
||||
@click="installAgent(agent)"
|
||||
@click="installSkill(skill)"
|
||||
>
|
||||
{{ t('Install') }}
|
||||
</n-button>
|
||||
@ -103,7 +100,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 分页 -->
|
||||
<div class="pagination-container">
|
||||
<n-pagination
|
||||
v-model:page="page"
|
||||
@ -112,7 +108,7 @@
|
||||
show-size-picker
|
||||
:page-sizes="[20, 50, 100]"
|
||||
:page-size="pageSize"
|
||||
@update:page="loadAgents"
|
||||
@update:page="loadSkills"
|
||||
@update:page-size="handlePageSizeChange"
|
||||
/>
|
||||
</div>
|
||||
@ -120,12 +116,12 @@
|
||||
|
||||
<div v-if="loading" class="loading">
|
||||
<n-spin size="large">
|
||||
<template #description>{{ t('Loading agents...') }}</template>
|
||||
<template #description>{{ t('Loading skills...') }}</template>
|
||||
</n-spin>
|
||||
</div>
|
||||
|
||||
<div v-if="!loading && agents.length === 0" class="empty">
|
||||
<n-empty :description="t('No agents found')">
|
||||
<div v-if="!loading && skills.length === 0" class="empty">
|
||||
<n-empty :description="t('No skills found')">
|
||||
<template #icon>
|
||||
<n-icon><Icon icon="hugeicons:robotic" /></n-icon>
|
||||
</template>
|
||||
@ -133,14 +129,13 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 安装进度弹窗 -->
|
||||
<InstallProgressModal
|
||||
v-model="showProgressModal"
|
||||
:progress="installProgress"
|
||||
:message="installMessage"
|
||||
:status="installStatus"
|
||||
:installing="installing"
|
||||
:title="t('Installing Agent')"
|
||||
:title="t('Installing Skill')"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -160,23 +155,20 @@ const router = useRouter()
|
||||
|
||||
const searchQuery = ref('')
|
||||
const loading = ref(false)
|
||||
const agents = ref<any[]>([])
|
||||
const skills = ref<any[]>([])
|
||||
const total = ref(0)
|
||||
const page = ref(1)
|
||||
const pageSize = ref(parseInt(localStorage.getItem('itemsPerPage') || '20'))
|
||||
const sortBy = ref('creation desc')
|
||||
|
||||
// 安装相关状态
|
||||
const installing = ref(false)
|
||||
const installProgress = ref(0)
|
||||
const installMessage = ref('')
|
||||
const installStatus = ref<'success' | 'error' | 'info'>('info')
|
||||
const showProgressModal = ref(false)
|
||||
|
||||
// 已安装智能体集合
|
||||
const installedAgentNames = ref<Set<string>>(new Set())
|
||||
const installedSkillNames = ref<Set<string>>(new Set())
|
||||
|
||||
// 排序选项
|
||||
const sortOptions = computed(() => [
|
||||
{ label: t('Latest'), value: 'creation desc' },
|
||||
{ label: t('Oldest'), value: 'creation asc' },
|
||||
@ -185,10 +177,9 @@ const sortOptions = computed(() => [
|
||||
{ label: t('Most Popular'), value: 'modified desc' }
|
||||
])
|
||||
|
||||
// 计算总页数
|
||||
const pageCount = computed(() => Math.max(1, Math.ceil(total.value / pageSize.value)))
|
||||
|
||||
async function loadAgents() {
|
||||
async function loadSkills() {
|
||||
loading.value = true
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
@ -201,19 +192,17 @@ async function loadAgents() {
|
||||
const response = await axios.get(`/jingrow/skill-marketplace?${params}`)
|
||||
const data = response.data
|
||||
|
||||
// 如果API返回分页数据
|
||||
if (data.items) {
|
||||
agents.value = data.items
|
||||
skills.value = data.items
|
||||
total.value = data.total || 0
|
||||
} else {
|
||||
// 兼容旧API格式
|
||||
agents.value = data || []
|
||||
total.value = agents.value.length
|
||||
skills.value = data || []
|
||||
total.value = skills.value.length
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load agents:', error)
|
||||
message.error(t('Failed to load agents'))
|
||||
agents.value = []
|
||||
console.error('Failed to load skills:', error)
|
||||
message.error(t('Failed to load skills'))
|
||||
skills.value = []
|
||||
total.value = 0
|
||||
} finally {
|
||||
loading.value = false
|
||||
@ -224,51 +213,48 @@ function handlePageSizeChange(newPageSize: number) {
|
||||
pageSize.value = newPageSize
|
||||
page.value = 1
|
||||
localStorage.setItem('itemsPerPage', newPageSize.toString())
|
||||
loadAgents()
|
||||
loadSkills()
|
||||
}
|
||||
|
||||
function viewAgentDetail(agent: any) {
|
||||
// 跳转到智能体详情页面,传递返回路径
|
||||
function viewSkillDetail(skill: any) {
|
||||
router.push({
|
||||
path: `/skill-marketplace/${agent.name}`,
|
||||
path: `/skill-marketplace/${skill.name}`,
|
||||
query: { returnTo: '/skill-marketplace' }
|
||||
})
|
||||
}
|
||||
|
||||
async function installAgent(agent: any) {
|
||||
if (!agent.skill_flow && !agent.skill_name) {
|
||||
message.error(t('Agent flow data or name is missing'))
|
||||
async function installSkill(skill: any) {
|
||||
if (!skill.skill_flow && !skill.skill_name) {
|
||||
message.error(t('Skill flow data or name is missing'))
|
||||
return
|
||||
}
|
||||
|
||||
// 先检查智能体是否已存在
|
||||
try {
|
||||
const skillName = agent.skill_name || agent.name
|
||||
const skillName = skill.skill_name || skill.name
|
||||
if (skillName) {
|
||||
const checkResponse = await axios.get(`/jingrow/check-agent/${skillName}`)
|
||||
const checkResponse = await axios.get(`/jingrow/check-skill/${skillName}`)
|
||||
|
||||
if (checkResponse.data.exists) {
|
||||
// 显示确认对话框
|
||||
dialog.warning({
|
||||
title: t('Agent already exists'),
|
||||
content: t('Agent "{0}" is already installed, do you want to overwrite?').replace('{0}', skillName),
|
||||
title: t('Skill already exists'),
|
||||
content: t('Skill "{0}" is already installed, do you want to overwrite?').replace('{0}', skillName),
|
||||
positiveText: t('Confirm Overwrite'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: () => {
|
||||
performInstall(agent)
|
||||
performInstall(skill)
|
||||
}
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Check agent exists error:', error)
|
||||
console.error('Check skill exists error:', error)
|
||||
}
|
||||
|
||||
performInstall(agent)
|
||||
performInstall(skill)
|
||||
}
|
||||
|
||||
async function performInstall(agent: any) {
|
||||
async function performInstall(skill: any) {
|
||||
try {
|
||||
installing.value = true
|
||||
installProgress.value = 0
|
||||
@ -276,41 +262,38 @@ async function performInstall(agent: any) {
|
||||
installStatus.value = 'info'
|
||||
showProgressModal.value = true
|
||||
|
||||
// 如果没有流程数据,先获取详情
|
||||
let skillFlow = agent.skill_flow
|
||||
let skillName = agent.skill_name || agent.name
|
||||
let skillFlow = skill.skill_flow
|
||||
let skillName = skill.skill_name || skill.name
|
||||
|
||||
if (!skillFlow) {
|
||||
installMessage.value = t('Fetching agent details...')
|
||||
installMessage.value = t('Fetching skill details...')
|
||||
installProgress.value = 20
|
||||
|
||||
try {
|
||||
const detailResponse = await axios.get(`/jingrow/skill-marketplace/${agent.name}`)
|
||||
const detailResponse = await axios.get(`/jingrow/skill-marketplace/${skill.name}`)
|
||||
const detail = detailResponse.data
|
||||
skillFlow = detail.skill_flow
|
||||
skillName = detail.skill_name || skillName
|
||||
} catch (error) {
|
||||
throw new Error(t('Failed to fetch agent details'))
|
||||
throw new Error(t('Failed to fetch skill details'))
|
||||
}
|
||||
}
|
||||
|
||||
if (!skillFlow) {
|
||||
throw new Error(t('Agent flow data is missing'))
|
||||
throw new Error(t('Skill flow data is missing'))
|
||||
}
|
||||
|
||||
installProgress.value = 40
|
||||
installMessage.value = t('Installing agent...')
|
||||
installMessage.value = t('Installing skill...')
|
||||
|
||||
// 如果 skill_flow 是字符串,尝试解析为 JSON
|
||||
if (typeof skillFlow === 'string') {
|
||||
try {
|
||||
skillFlow = JSON.parse(skillFlow)
|
||||
} catch (e) {
|
||||
// 如果解析失败,保持原样
|
||||
}
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/install-agent', {
|
||||
const response = await axios.post('/jingrow/install-skill', {
|
||||
skill_name: skillName,
|
||||
skill_flow: skillFlow
|
||||
}, {
|
||||
@ -319,18 +302,15 @@ async function performInstall(agent: any) {
|
||||
}
|
||||
})
|
||||
|
||||
// 更新进度到安装完成
|
||||
installProgress.value = 100
|
||||
|
||||
if (response.data.success) {
|
||||
// 所有步骤完成后才显示成功
|
||||
installing.value = false
|
||||
installStatus.value = 'success'
|
||||
installMessage.value = t('Agent installed successfully!')
|
||||
message.success(t('Agent installed successfully'))
|
||||
installMessage.value = t('Skill installed successfully!')
|
||||
message.success(t('Skill installed successfully'))
|
||||
|
||||
// 刷新已安装智能体列表
|
||||
loadInstalledAgents()
|
||||
loadInstalledSkills()
|
||||
|
||||
setTimeout(() => {
|
||||
showProgressModal.value = false
|
||||
@ -339,7 +319,7 @@ async function performInstall(agent: any) {
|
||||
throw new Error(response.data.error || t('Installation failed'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('Install agent error:', error)
|
||||
console.error('Install skill error:', error)
|
||||
installing.value = false
|
||||
installStatus.value = 'error'
|
||||
installMessage.value = error.response?.data?.detail || error.message || t('Installation failed')
|
||||
@ -357,52 +337,46 @@ function truncateText(text: string, maxLength: number): string {
|
||||
return text.substring(0, maxLength) + '...'
|
||||
}
|
||||
|
||||
// 加载已安装智能体列表
|
||||
async function loadInstalledAgents() {
|
||||
async function loadInstalledSkills() {
|
||||
try {
|
||||
const response = await axios.get('/jingrow/installed-skill-names')
|
||||
if (response.data.success) {
|
||||
const agents = response.data.agents || []
|
||||
installedAgentNames.value = new Set(agents.map((a: string) => a.toLowerCase()))
|
||||
const skills = response.data.skills || []
|
||||
installedSkillNames.value = new Set(skills.map((a: string) => a.toLowerCase()))
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Load installed agents error:', error)
|
||||
console.error('Load installed skills error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查智能体是否已安装
|
||||
function isAgentInstalled(skillName: string): boolean {
|
||||
function isSkillInstalled(skillName: string): boolean {
|
||||
if (!skillName) return false
|
||||
return installedAgentNames.value.has(skillName.toLowerCase())
|
||||
return installedSkillNames.value.has(skillName.toLowerCase())
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
loadAgents()
|
||||
loadInstalledAgents()
|
||||
loadSkills()
|
||||
loadInstalledSkills()
|
||||
|
||||
// 监听全局事件
|
||||
window.addEventListener('installedAgentsUpdated', () => {
|
||||
loadInstalledAgents()
|
||||
window.addEventListener('installedSkillsUpdated', () => {
|
||||
loadInstalledSkills()
|
||||
})
|
||||
})
|
||||
|
||||
// 监听排序变化(搜索改为手动触发)
|
||||
watch([sortBy], () => {
|
||||
page.value = 1 // 重置到第一页
|
||||
loadAgents()
|
||||
page.value = 1
|
||||
loadSkills()
|
||||
}, { deep: true })
|
||||
|
||||
// 监听分页变化
|
||||
watch([page], () => {
|
||||
loadAgents()
|
||||
loadSkills()
|
||||
})
|
||||
|
||||
// 监听每页数量变化(从系统设置)
|
||||
watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
if (newValue) {
|
||||
pageSize.value = parseInt(newValue)
|
||||
page.value = 1 // 重置到第一页
|
||||
loadAgents()
|
||||
page.value = 1
|
||||
loadSkills()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
@ -441,11 +415,11 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.agents-section {
|
||||
.skills-section {
|
||||
margin-bottom: 32px;
|
||||
}
|
||||
|
||||
.agents-header {
|
||||
.skills-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
@ -506,7 +480,7 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.3);
|
||||
}
|
||||
|
||||
.agents-grid {
|
||||
.skills-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 24px;
|
||||
@ -619,10 +593,9 @@ watch(() => localStorage.getItem('itemsPerPage'), (newValue) => {
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.agents-grid {
|
||||
.skills-grid {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 16px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@ -3,8 +3,8 @@
|
||||
<div v-if="!hasValidParams" class="empty-state">
|
||||
<div class="empty-content">
|
||||
<h3>{{ t('Flow Builder') }}</h3>
|
||||
<p>{{ t('Please enter from Agents page to open Flow Builder') }}</p>
|
||||
<n-button type="primary" @click="goToAgents">{{ t('View Agents') }}</n-button>
|
||||
<p>{{ t('Please enter from Skills page to open Flow Builder') }}</p>
|
||||
<n-button type="primary" @click="goToSkills">{{ t('View Skills') }}</n-button>
|
||||
</div>
|
||||
</div>
|
||||
<FlowBuilderContainer
|
||||
@ -21,7 +21,7 @@ import { computed, onMounted } from 'vue'
|
||||
import { useRouter, useRoute } from 'vue-router'
|
||||
import { useMessage, NButton } from 'naive-ui'
|
||||
import FlowBuilderContainer from '@/core/features/flows/FlowBuilderContainer.vue'
|
||||
import { useSkillStore } from '@/shared/stores/agent'
|
||||
import { useSkillStore } from '@/shared/stores/skill'
|
||||
import { useFlowBuilderStore } from '@/shared/stores/flowBuilder'
|
||||
import { slugToPageType } from '@/shared/utils/slug'
|
||||
import { t } from '@/shared/i18n'
|
||||
@ -34,7 +34,7 @@ const flowBuilderStore = useFlowBuilderStore()
|
||||
|
||||
// 计算属性 - 从 URL 获取参数
|
||||
const name = computed(() => {
|
||||
return (route.query.id as string) || (route.query.name as string) || flowBuilderStore.getAgentId()
|
||||
return (route.query.id as string) || (route.query.name as string) || flowBuilderStore.getSkillId()
|
||||
})
|
||||
|
||||
const pagetype = computed(() => {
|
||||
@ -52,13 +52,13 @@ onMounted(async () => {
|
||||
const urlName = (route.query.id as string) || (route.query.name as string)
|
||||
const urlPageType = pagetype.value
|
||||
|
||||
if (urlName && !flowBuilderStore.getAgentId()) {
|
||||
if (urlName && !flowBuilderStore.getSkillId()) {
|
||||
try {
|
||||
// 获取智能体数据
|
||||
await skillStore.fetchSkill(urlName, urlPageType)
|
||||
const agent = skillStore.currentSkill
|
||||
if (agent?.skill_flow) {
|
||||
let flowData = agent.skill_flow
|
||||
const skill = skillStore.currentSkill
|
||||
if (skill?.skill_flow) {
|
||||
let flowData = skill.skill_flow
|
||||
if (typeof flowData === 'string') {
|
||||
flowData = JSON.parse(flowData)
|
||||
}
|
||||
@ -76,7 +76,7 @@ const handleSave = async (flowData: any) => {
|
||||
if (name.value) {
|
||||
// 保存到智能体
|
||||
await skillStore.updateSkill(name.value, { skill_flow: flowData }, pagetype.value)
|
||||
message.success(t('Agent flow saved successfully'))
|
||||
message.success(t('Skill flow saved successfully'))
|
||||
// 保存成功后清理 store 状态
|
||||
flowBuilderStore.deactivateFlowBuilder()
|
||||
} else {
|
||||
@ -88,8 +88,8 @@ const handleSave = async (flowData: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
const goToAgents = () => {
|
||||
router.push('/agents')
|
||||
const goToSkills = () => {
|
||||
router.push('/skills')
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@ -370,7 +370,7 @@ async function performPublish() {
|
||||
skill_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/agent/publish', publishData, {
|
||||
const response = await axios.post('/jingrow/skill/publish', publishData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
@ -294,7 +294,7 @@ async function performPublish() {
|
||||
skill_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/agent/publish', publishData, {
|
||||
const response = await axios.post('/jingrow/skill/publish', publishData, {
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
|
||||
@ -45,7 +45,7 @@
|
||||
"fieldname": "action_type",
|
||||
"fieldtype": "Select",
|
||||
"label": "Action Type",
|
||||
"options": "\ncreate_pagetype\ncreate_record\nupdate_record\nread_record\nexecute_agent\nsearch_records\nhttp_request",
|
||||
"options": "\ncreate_pagetype\ncreate_record\nupdate_record\nread_record\nexecute_skill\nsearch_records\nhttp_request",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@ -18,7 +18,7 @@ class AiChatAction(Page):
|
||||
action_input: DF.JSON | None
|
||||
action_output: DF.JSON | None
|
||||
action_status: DF.Literal["pending", "running", "completed", "failed"]
|
||||
action_type: DF.Literal["", "create_pagetype", "create_record", "update_record", "read_record", "execute_agent", "search_records", "http_request"]
|
||||
action_type: DF.Literal["", "create_pagetype", "create_record", "update_record", "read_record", "execute_skill", "search_records", "http_request"]
|
||||
chat: DF.Link
|
||||
completed_at: DF.Datetime | None
|
||||
error_message: DF.Text | None
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"progress",
|
||||
"section_break_xcls",
|
||||
"column_break_glmw",
|
||||
"skill_name"
|
||||
"skill_name",
|
||||
"ai_repeat",
|
||||
"enabled",
|
||||
"column_break_bzai",
|
||||
@ -20,8 +20,8 @@
|
||||
"target_module",
|
||||
"condition",
|
||||
"trigger_time",
|
||||
"skill_flow_tab"
|
||||
"skill_flow"
|
||||
"skill_flow_tab",
|
||||
"skill_flow",
|
||||
"排除关键词_tab",
|
||||
"exclude_prompts"
|
||||
],
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"creation": "2026-06-24 10:00:00.000000",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"skill_name"
|
||||
"skill_name",
|
||||
"status",
|
||||
"column_break_basic",
|
||||
"start_time",
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"progress",
|
||||
"section_break_xcls",
|
||||
"column_break_glmw",
|
||||
"skill_name"
|
||||
"skill_name",
|
||||
"ai_repeat",
|
||||
"enabled",
|
||||
"column_break_bzai",
|
||||
@ -20,8 +20,8 @@
|
||||
"target_module",
|
||||
"condition",
|
||||
"trigger_time",
|
||||
"skill_flow_tab"
|
||||
"skill_flow"
|
||||
"skill_flow_tab",
|
||||
"skill_flow",
|
||||
"排除关键词_tab",
|
||||
"exclude_prompts"
|
||||
],
|
||||
|
||||
@ -50,7 +50,7 @@ class LocalAiSkill(Page):
|
||||
"""
|
||||
skill_id = self.name
|
||||
cron = getattr(self, "trigger_time", None) or getattr(self, "cron_format", None)
|
||||
method_name = f"jingrow/agents/execute_scheduled_skill:{skill_id}"
|
||||
method_name = f"jingrow/skills/execute_scheduled_skill:{skill_id}"
|
||||
|
||||
# 检查是否存在对应的定时任务
|
||||
job = jingrow.db.exists("Local Scheduled Job", {"method": method_name})
|
||||
|
||||
@ -102,18 +102,17 @@ def execute(params: dict, context=None) -> dict:
|
||||
if not template:
|
||||
return {"success": False, "error": "AI 内容生成节点缺少模板配置 (ai_user_content)"}
|
||||
|
||||
# 构建模板上下文,注入 Agent 字段
|
||||
template_context = inputs.copy()
|
||||
agent_data = {}
|
||||
skill_data = {}
|
||||
if ctx and "flow_id" in ctx and ctx["flow_id"]:
|
||||
try:
|
||||
agent = jingrow.get_pg("Ai Skill", ctx["flow_id"])
|
||||
if agent:
|
||||
agent_data = agent.as_dict()
|
||||
skill = jingrow.get_pg("Ai Skill", ctx["flow_id"])
|
||||
if skill:
|
||||
skill_data = skill.as_dict()
|
||||
except Exception as e:
|
||||
jingrow.log_error("ai_content_generation: agent data error", str(e))
|
||||
jingrow.log_error("ai_content_generation: skill data error", str(e))
|
||||
|
||||
for key, value in agent_data.items():
|
||||
for key, value in skill_data.items():
|
||||
if key not in template_context or not template_context.get(key):
|
||||
template_context[key] = value
|
||||
|
||||
|
||||
@ -198,15 +198,15 @@ def execute(params: dict, context=None) -> dict:
|
||||
|
||||
# 构建模板上下文
|
||||
template_context = inputs.copy()
|
||||
agent_data = {}
|
||||
skill_data = {}
|
||||
if ctx and "flow_id" in ctx and ctx["flow_id"]:
|
||||
try:
|
||||
agent = jingrow.get_pg("Ai Skill", ctx["flow_id"])
|
||||
if agent:
|
||||
agent_data = agent.as_dict()
|
||||
skill = jingrow.get_pg("Ai Skill", ctx["flow_id"])
|
||||
if skill:
|
||||
skill_data = skill.as_dict()
|
||||
except Exception as e:
|
||||
jingrow.log_error("ai_image_generation: agent data error", str(e))
|
||||
for key, value in agent_data.items():
|
||||
jingrow.log_error("ai_image_generation: skill data error", str(e))
|
||||
for key, value in skill_data.items():
|
||||
if key not in template_context or not template_context.get(key):
|
||||
template_context[key] = value
|
||||
|
||||
|
||||
@ -137,7 +137,7 @@ class ToolRegistry:
|
||||
return result
|
||||
|
||||
@classmethod
|
||||
def get_agent_definitions(cls) -> list:
|
||||
def get_skill_definitions(cls) -> list:
|
||||
"""返回 Agent 流程可用的 Tool 列表(含 UI 元数据)
|
||||
|
||||
用于 Agent 流程编辑器渲染节点面板。
|
||||
|
||||
@ -57,10 +57,10 @@ def get_local_ai_skills_list(page: int = 1, page_size: int = 10, fields: List =
|
||||
if filters:
|
||||
query_kwargs["filters"] = filters
|
||||
|
||||
agents = jingrow.get_list("Local Ai Skill", **query_kwargs)
|
||||
skills = jingrow.get_list("Local Ai Skill", **query_kwargs)
|
||||
|
||||
return {
|
||||
"items": agents or [],
|
||||
"items": skills or [],
|
||||
"total": total,
|
||||
"page": page,
|
||||
"page_size": page_size
|
||||
@ -81,7 +81,7 @@ def get_local_ai_skill_detail(name: str) -> Optional[Dict]:
|
||||
获取单个AI智能体详情
|
||||
"""
|
||||
try:
|
||||
agents = jingrow.get_list(
|
||||
skills = jingrow.get_list(
|
||||
pagetype='Local Ai Skill',
|
||||
fields=['name', 'skill_name', 'status', 'enabled', 'trigger_mode',
|
||||
'progress', 'ai_repeat', 'creation', 'modified', 'modified_by',
|
||||
@ -91,7 +91,7 @@ def get_local_ai_skill_detail(name: str) -> Optional[Dict]:
|
||||
limit_page_length=1
|
||||
)
|
||||
|
||||
if not agents:
|
||||
if not skills:
|
||||
return {
|
||||
'success': False,
|
||||
'message': 'Local Ai Skill不存在',
|
||||
@ -101,7 +101,7 @@ def get_local_ai_skill_detail(name: str) -> Optional[Dict]:
|
||||
return {
|
||||
'success': True,
|
||||
'message': '获取成功',
|
||||
'data': agents[0]
|
||||
'data': skills[0]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
@ -186,19 +186,19 @@ def get_available_node_types() -> List[str]:
|
||||
def update_local_ai_skill(name: str, data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
||||
try:
|
||||
agent = jingrow.get_pg('Local Ai Skill', name)
|
||||
skill = jingrow.get_pg('Local Ai Skill', name)
|
||||
for field, value in data.items():
|
||||
if hasattr(agent, field):
|
||||
field_type = getattr(agent.meta, 'get_field', lambda x: None)(field)
|
||||
if hasattr(skill, field):
|
||||
field_type = getattr(skill.meta, 'get_field', lambda x: None)(field)
|
||||
if field_type and field_type.fieldtype == 'JSON' and isinstance(value, dict):
|
||||
# JSON 字段保持格式化
|
||||
import json
|
||||
setattr(agent, field, json.dumps(value, ensure_ascii=False, indent=2))
|
||||
setattr(skill, field, json.dumps(value, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
setattr(agent, field, value)
|
||||
setattr(skill, field, value)
|
||||
|
||||
# 保存更新
|
||||
agent.save()
|
||||
skill.save()
|
||||
jingrow.db.commit()
|
||||
|
||||
return {
|
||||
@ -220,14 +220,14 @@ def get_jflow_dashboard_stats() -> Dict[str, Any]:
|
||||
"""
|
||||
try:
|
||||
# 获取AI智能体统计
|
||||
agents_result = get_local_ai_skills_list(page=1, page_size=1000)
|
||||
agents = agents_result.get('items', [])
|
||||
skills_result = get_local_ai_skills_list(page=1, page_size=1000)
|
||||
skills = skills_result.get('items', [])
|
||||
|
||||
stats = {
|
||||
'total_agents': len(agents),
|
||||
'enabled_agents': len([a for a in agents if a.get('enabled', False)]),
|
||||
'active_agents': len([a for a in agents if a.get('status') == '进行中']),
|
||||
'completed_agents': len([a for a in agents if a.get('status') == '已完成']),
|
||||
'total_skills': len(skills),
|
||||
'enabled_skills': len([a for a in skills if a.get('enabled', False)]),
|
||||
'active_skills': len([a for a in skills if a.get('status') == '进行中']),
|
||||
'completed_skills': len([a for a in skills if a.get('status') == '已完成']),
|
||||
'total_nodes': len(get_available_node_types()),
|
||||
'total_executions': 0, # 这里可以添加执行记录统计
|
||||
'active_flows': 0 # 这里可以添加流程统计
|
||||
@ -238,10 +238,10 @@ def get_jflow_dashboard_stats() -> Dict[str, Any]:
|
||||
except Exception as e:
|
||||
jingrow.log_error("获取仪表板统计失败", str(e))
|
||||
return {
|
||||
'total_agents': 0,
|
||||
'enabled_agents': 0,
|
||||
'active_agents': 0,
|
||||
'completed_agents': 0,
|
||||
'total_skills': 0,
|
||||
'enabled_skills': 0,
|
||||
'active_skills': 0,
|
||||
'completed_skills': 0,
|
||||
'total_nodes': 0,
|
||||
'total_executions': 0,
|
||||
'active_flows': 0
|
||||
|
||||
@ -362,7 +362,7 @@ def get_directory_size(*path):
|
||||
|
||||
def _get_directory_size(*path):
|
||||
folder = os.path.abspath(jingrow.get_site_path(*path))
|
||||
# Copied as is from agent
|
||||
# Copied as is from skill
|
||||
total_size = os.path.getsize(folder)
|
||||
for item in os.listdir(folder):
|
||||
itempath = os.path.join(folder, item)
|
||||
|
||||
@ -83,7 +83,7 @@ website_route_rules = [
|
||||
{"from_route": "/publish-app", "to_route": "app"},
|
||||
{"from_route": "/my-published-apps", "to_route": "app"},
|
||||
{"from_route": "/my-published-nodes", "to_route": "app"},
|
||||
{"from_route": "/my-published-agents", "to_route": "app"},
|
||||
{"from_route": "/my-published-skills", "to_route": "app"},
|
||||
{"from_route": "/my-published-tools", "to_route": "app"},
|
||||
{"from_route": "/page/<path:page_path>", "to_route": "app"},
|
||||
{"from_route": "/mindmap", "to_route": "app"},
|
||||
|
||||
@ -18656,7 +18656,7 @@ msgstr "智能体 \"{0}\" 已安装,是否覆盖安装?"
|
||||
msgid "Agent Detail"
|
||||
msgstr "智能体详情"
|
||||
|
||||
msgid "Agent Marketplace"
|
||||
msgid "Skill Marketplace"
|
||||
msgstr "智能体市场"
|
||||
|
||||
msgid "Agent Name"
|
||||
@ -18815,7 +18815,7 @@ msgstr "应用标题是必填项"
|
||||
msgid "Applications"
|
||||
msgstr "应用列表"
|
||||
|
||||
msgid "Are you sure to delete this agent?"
|
||||
msgid "Are you sure to delete this skill?"
|
||||
msgstr "确定要删除这个智能体吗?"
|
||||
|
||||
msgid "Are you sure to reset menus to default? This will overwrite current settings."
|
||||
@ -18824,7 +18824,7 @@ msgstr "确定恢复默认菜单?当前自定义将被覆盖。"
|
||||
msgid "Are you sure you want to delete"
|
||||
msgstr "确定要删除"
|
||||
|
||||
msgid "Are you sure you want to delete agent \"{0}\"? This action cannot be undone."
|
||||
msgid "Are you sure you want to delete skill \"{0}\"? This action cannot be undone."
|
||||
msgstr "确定要删除智能体 \"{0}\" 吗?此操作不可恢复。"
|
||||
|
||||
msgid "Are you sure you want to delete all recent activities? This action cannot be undone."
|
||||
@ -18836,7 +18836,7 @@ msgstr "确定删除菜单"
|
||||
msgid "Are you sure you want to delete node \"{0}\"? This action cannot be undone."
|
||||
msgstr "确定要删除节点 \"{0}\" 吗?此操作不可恢复。"
|
||||
|
||||
msgid "Are you sure you want to delete the selected agents? This action cannot be undone."
|
||||
msgid "Are you sure you want to delete the selected skills? This action cannot be undone."
|
||||
msgstr "确定要删除选中的智能体吗?此操作无法撤销。"
|
||||
|
||||
msgid "Are you sure you want to delete the selected jobs? This action cannot be undone."
|
||||
@ -18869,7 +18869,7 @@ msgstr "确定要删除 {count} 条选中的记录吗?此操作无法撤销。
|
||||
msgid "Are you sure you want to hide default tool"
|
||||
msgstr "确定要隐藏默认工具"
|
||||
|
||||
msgid "Are you sure you want to publish agent \"{0}\" to the marketplace?"
|
||||
msgid "Are you sure you want to publish skill \"{0}\" to the marketplace?"
|
||||
msgstr "确定要将智能体 \"{0}\" 发布到市场吗?"
|
||||
|
||||
msgid "Are you sure you want to publish node \"{0}\" to the marketplace?"
|
||||
@ -18971,7 +18971,7 @@ msgstr "布尔值"
|
||||
msgid "Brief description"
|
||||
msgstr "简要描述"
|
||||
|
||||
msgid "Browse and install agents from Jingrow Agent Marketplace"
|
||||
msgid "Browse and install skills from Jingrow Skill Marketplace"
|
||||
msgstr "浏览并安装来自 Jingrow 智能体市场的智能体"
|
||||
|
||||
msgid "Browse and install applications from Jingrow App Marketplace"
|
||||
@ -19154,7 +19154,7 @@ msgstr "创建页面类型模板文件"
|
||||
msgid "Create a modern, efficient template app"
|
||||
msgstr "创建一个现代化、高效的应用模板"
|
||||
|
||||
msgid "Create a new AI agent"
|
||||
msgid "Create a new AI skill"
|
||||
msgstr "创建新的AI智能体"
|
||||
|
||||
msgid "Create a new application for the marketplace"
|
||||
@ -19169,7 +19169,7 @@ msgstr "创建失败"
|
||||
msgid "Create your account"
|
||||
msgstr "创建您的账户"
|
||||
|
||||
msgid "Created a new agent"
|
||||
msgid "Created a new skill"
|
||||
msgstr "创建了新的智能体"
|
||||
|
||||
msgid "Created successfully"
|
||||
@ -19475,7 +19475,7 @@ msgstr "下载失败"
|
||||
msgid "Failed to export app package"
|
||||
msgstr "导出应用安装包失败"
|
||||
|
||||
msgid "Failed to fetch agent details"
|
||||
msgid "Failed to fetch skill details"
|
||||
msgstr "获取智能体详情失败"
|
||||
|
||||
msgid "Failed to install app"
|
||||
@ -19484,13 +19484,13 @@ msgstr "安装应用失败"
|
||||
msgid "Failed to load Schema Editor"
|
||||
msgstr "加载 Schema 编辑器失败"
|
||||
|
||||
msgid "Failed to load agent detail"
|
||||
msgid "Failed to load skill detail"
|
||||
msgstr "获取智能体详情失败"
|
||||
|
||||
msgid "Failed to load agent details"
|
||||
msgid "Failed to load skill details"
|
||||
msgstr "加载智能体详情失败"
|
||||
|
||||
msgid "Failed to load agents"
|
||||
msgid "Failed to load skills"
|
||||
msgstr "加载智能体失败"
|
||||
|
||||
msgid "Failed to load app details"
|
||||
@ -19640,7 +19640,7 @@ msgstr "Feather"
|
||||
msgid "Feedback & Suggestions"
|
||||
msgstr "反馈建议"
|
||||
|
||||
msgid "Fetching agent details..."
|
||||
msgid "Fetching skill details..."
|
||||
msgstr "正在获取智能体详情..."
|
||||
|
||||
msgid "Field ID"
|
||||
@ -19805,7 +19805,7 @@ msgstr "正在安装应用"
|
||||
msgid "Installing Node"
|
||||
msgstr "正在安装节点"
|
||||
|
||||
msgid "Installing agent..."
|
||||
msgid "Installing skill..."
|
||||
msgstr "正在安装智能体..."
|
||||
|
||||
msgid "Installing extension package..."
|
||||
@ -19838,7 +19838,7 @@ msgstr "内部路径:/example"
|
||||
msgid "Invalid JSON, please fix before saving"
|
||||
msgstr "JSON 格式错误,请修正后再保存"
|
||||
|
||||
msgid "Invalid agent flow data format"
|
||||
msgid "Invalid skill flow data format"
|
||||
msgstr "智能体流程数据格式无效"
|
||||
|
||||
msgid "Is Featured"
|
||||
@ -20012,10 +20012,10 @@ msgstr "让我们通过几个简单的步骤来设置您的系统"
|
||||
msgid "Load failed"
|
||||
msgstr "加载失败"
|
||||
|
||||
msgid "Loading agent details..."
|
||||
msgid "Loading skill details..."
|
||||
msgstr "加载智能体详情中..."
|
||||
|
||||
msgid "Loading agents..."
|
||||
msgid "Loading skills..."
|
||||
msgstr "加载智能体中..."
|
||||
|
||||
msgid "Loading application details..."
|
||||
@ -20078,7 +20078,7 @@ msgstr "管理智能体"
|
||||
msgid "Manage Nodes"
|
||||
msgstr "管理节点"
|
||||
|
||||
msgid "Manage and configure your AI agents workflows"
|
||||
msgid "Manage and configure your AI skills workflows"
|
||||
msgstr "管理和配置您的AI智能体工作流"
|
||||
|
||||
msgid "Manage and configure your AI node components"
|
||||
@ -20096,7 +20096,7 @@ msgstr "管理导航菜单项"
|
||||
msgid "Manage your locally installed applications"
|
||||
msgstr "管理您本地安装的应用"
|
||||
|
||||
msgid "Manage your published agents in the marketplace"
|
||||
msgid "Manage your published skills in the marketplace"
|
||||
msgstr "管理您在市场中发布的智能体"
|
||||
|
||||
msgid "Manage your published applications in the marketplace"
|
||||
@ -20198,7 +20198,7 @@ msgstr "暂无工具"
|
||||
msgid "No activities to delete"
|
||||
msgstr "没有活动可删除"
|
||||
|
||||
msgid "No agents found"
|
||||
msgid "No skills found"
|
||||
msgstr "未找到智能体"
|
||||
|
||||
msgid "No applications found"
|
||||
@ -20474,10 +20474,10 @@ msgstr "请输入有效的图片URL"
|
||||
msgid "Please enter a valid phone number"
|
||||
msgstr "请输入有效的手机号码"
|
||||
|
||||
msgid "Please enter agent description"
|
||||
msgid "Please enter skill description"
|
||||
msgstr "请输入智能体描述"
|
||||
|
||||
msgid "Please enter agent name"
|
||||
msgid "Please enter skill name"
|
||||
msgstr "请输入智能体名称"
|
||||
|
||||
msgid "Please enter an image URL"
|
||||
@ -20522,7 +20522,7 @@ msgstr "请先登录后才能下载"
|
||||
msgid "Please navigate to the path manually"
|
||||
msgstr "请手动导航到该路径"
|
||||
|
||||
msgid "Please save the agent first"
|
||||
msgid "Please save the skill first"
|
||||
msgstr "请先保存智能体"
|
||||
|
||||
msgid "Please save the node first"
|
||||
@ -20615,7 +20615,7 @@ msgstr "发布失败"
|
||||
msgid "Publish failed, please check permission and server logs"
|
||||
msgstr "发布失败,请检查权限和服务器日志"
|
||||
|
||||
msgid "Publish to Agent Marketplace"
|
||||
msgid "Publish to Skill Marketplace"
|
||||
msgstr "发布到智能体市场"
|
||||
|
||||
msgid "Publish to Marketplace"
|
||||
@ -20798,7 +20798,7 @@ msgstr "定时任务"
|
||||
msgid "Schema saved successfully"
|
||||
msgstr "Schema 保存成功"
|
||||
|
||||
msgid "Search agents..."
|
||||
msgid "Search skills..."
|
||||
msgstr "搜索智能体..."
|
||||
|
||||
msgid "Search applications..."
|
||||
@ -21287,7 +21287,7 @@ msgstr "查看结果"
|
||||
msgid "View Workflow"
|
||||
msgstr "查看工作流"
|
||||
|
||||
msgid "View and manage agent settings"
|
||||
msgid "View and manage skill settings"
|
||||
msgstr "查看和管理智能体配置"
|
||||
|
||||
msgid "View and manage scheduled job settings"
|
||||
@ -22912,7 +22912,7 @@ msgstr "更新记录"
|
||||
msgid "read_record"
|
||||
msgstr "读取记录"
|
||||
|
||||
msgid "execute_agent"
|
||||
msgid "execute_skill"
|
||||
msgstr "执行智能体"
|
||||
|
||||
msgid "search_records"
|
||||
@ -22963,7 +22963,7 @@ msgstr "skill_name不能为空"
|
||||
msgid "Ai Agent {0} does not exist"
|
||||
msgstr "Ai Agent {0} 不存在"
|
||||
|
||||
msgid "The agent execution task has been queued. Please check the execution status later."
|
||||
msgid "The skill execution task has been queued. Please check the execution status later."
|
||||
msgstr "智能体执行任务已加入队列,请稍后查看执行状态"
|
||||
|
||||
msgid "Ai Agent Execution Log creation failed"
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
.skill-marketplace[data-v-14e257e5]{padding:24px}.page-header[data-v-14e257e5]{margin-bottom:32px}.header-content[data-v-14e257e5]{display:flex;justify-content:space-between;align-items:flex-start}.header-text h1[data-v-14e257e5]{margin:0 0 8px;font-size:28px;font-weight:700;color:#1a1a1a}.header-text p[data-v-14e257e5]{margin:0;color:#666;font-size:16px}.search-container[data-v-14e257e5]{display:flex;justify-content:center;margin-bottom:32px}.agents-section[data-v-14e257e5]{margin-bottom:32px}.agents-header[data-v-14e257e5]{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.sort-controls[data-v-14e257e5]{display:flex;align-items:center;gap:12px}.pagination-container[data-v-14e257e5]{display:flex;justify-content:center;margin-top:32px;padding:20px 0}.search-bar[data-v-14e257e5]{display:flex;gap:16px;align-items:center;max-width:600px;width:100%;padding:20px;background:linear-gradient(135deg,#f8fafc,#f1f5f9);border-radius:20px;border:1px solid #e2e8f0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.search-input[data-v-14e257e5]{flex:1;min-width:0}.search-input .n-input[data-v-14e257e5]{border-radius:12px;border:1px solid #d1d5db;transition:all .2s ease}.search-input .n-input[data-v-14e257e5]:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.search-button[data-v-14e257e5]{border-radius:12px;font-weight:600;padding:0 24px;transition:all .2s ease}.search-button[data-v-14e257e5]:hover{transform:translateY(-1px);box-shadow:0 4px 12px #3b82f64d}.agents-grid[data-v-14e257e5]{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:24px}.skill-card[data-v-14e257e5]{border:1px solid #e5e7eb;border-radius:16px;background:#fff;overflow:hidden;transition:all .3s ease;box-shadow:0 1px 3px #0000001a}.skill-card[data-v-14e257e5]:hover{transform:translateY(-4px);box-shadow:0 8px 25px #00000026;border-color:#d1d5db}.skill-icon[data-v-14e257e5]{display:flex;align-items:center;justify-content:center;width:100%;height:120px;background:linear-gradient(135deg,#f3f4f6,#e5e7eb);cursor:pointer;padding:20px}.skill-icon-placeholder[data-v-14e257e5]{display:flex;align-items:center;justify-content:center;width:100%;height:100%;color:#9ca3af}.skill-content[data-v-14e257e5]{padding:20px}.skill-header[data-v-14e257e5]{margin-bottom:12px}.skill-title-section[data-v-14e257e5]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.skill-title-section h3[data-v-14e257e5]{margin:0;font-size:18px;font-weight:600;color:#1f2937;line-height:1.2;flex:1;min-width:0}.clickable-title[data-v-14e257e5]{cursor:pointer;transition:color .2s ease}.clickable-title[data-v-14e257e5]:hover{color:#10b981}.skill-name[data-v-14e257e5]{color:#6b7280;font-size:11px;font-weight:500;font-family:SF Mono,Monaco,Menlo,Ubuntu Mono,monospace;background:#f3f4f6;border:1px solid #d1d5db;border-radius:8px;padding:4px 10px;display:inline-block;white-space:nowrap}.skill-description[data-v-14e257e5]{color:#6b7280;font-size:14px;line-height:1.5;margin-bottom:12px}.skill-actions[data-v-14e257e5]{padding:0 20px 20px;display:flex;gap:12px}.skill-actions .n-button[data-v-14e257e5]{flex:1}.loading[data-v-14e257e5],.empty[data-v-14e257e5]{display:flex;justify-content:center;align-items:center;min-height:300px}@media(max-width:768px){.agents-grid[data-v-14e257e5]{grid-template-columns:1fr;gap:16px}}
|
||||
.skill-marketplace[data-v-14e257e5]{padding:24px}.page-header[data-v-14e257e5]{margin-bottom:32px}.header-content[data-v-14e257e5]{display:flex;justify-content:space-between;align-items:flex-start}.header-text h1[data-v-14e257e5]{margin:0 0 8px;font-size:28px;font-weight:700;color:#1a1a1a}.header-text p[data-v-14e257e5]{margin:0;color:#666;font-size:16px}.search-container[data-v-14e257e5]{display:flex;justify-content:center;margin-bottom:32px}.skills-section[data-v-14e257e5]{margin-bottom:32px}.skills-header[data-v-14e257e5]{display:flex;justify-content:space-between;align-items:center;margin-bottom:24px}.sort-controls[data-v-14e257e5]{display:flex;align-items:center;gap:12px}.pagination-container[data-v-14e257e5]{display:flex;justify-content:center;margin-top:32px;padding:20px 0}.search-bar[data-v-14e257e5]{display:flex;gap:16px;align-items:center;max-width:600px;width:100%;padding:20px;background:linear-gradient(135deg,#f8fafc,#f1f5f9);border-radius:20px;border:1px solid #e2e8f0;box-shadow:0 4px 6px -1px #0000001a,0 2px 4px -1px #0000000f}.search-input[data-v-14e257e5]{flex:1;min-width:0}.search-input .n-input[data-v-14e257e5]{border-radius:12px;border:1px solid #d1d5db;transition:all .2s ease}.search-input .n-input[data-v-14e257e5]:focus-within{border-color:#3b82f6;box-shadow:0 0 0 3px #3b82f61a}.search-button[data-v-14e257e5]{border-radius:12px;font-weight:600;padding:0 24px;transition:all .2s ease}.search-button[data-v-14e257e5]:hover{transform:translateY(-1px);box-shadow:0 4px 12px #3b82f64d}.skills-grid[data-v-14e257e5]{display:grid;grid-template-columns:repeat(auto-fill,minmax(320px,1fr));gap:24px}.skill-card[data-v-14e257e5]{border:1px solid #e5e7eb;border-radius:16px;background:#fff;overflow:hidden;transition:all .3s ease;box-shadow:0 1px 3px #0000001a}.skill-card[data-v-14e257e5]:hover{transform:translateY(-4px);box-shadow:0 8px 25px #00000026;border-color:#d1d5db}.skill-icon[data-v-14e257e5]{display:flex;align-items:center;justify-content:center;width:100%;height:120px;background:linear-gradient(135deg,#f3f4f6,#e5e7eb);cursor:pointer;padding:20px}.skill-icon-placeholder[data-v-14e257e5]{display:flex;align-items:center;justify-content:center;width:100%;height:100%;color:#9ca3af}.skill-content[data-v-14e257e5]{padding:20px}.skill-header[data-v-14e257e5]{margin-bottom:12px}.skill-title-section[data-v-14e257e5]{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.skill-title-section h3[data-v-14e257e5]{margin:0;font-size:18px;font-weight:600;color:#1f2937;line-height:1.2;flex:1;min-width:0}.clickable-title[data-v-14e257e5]{cursor:pointer;transition:color .2s ease}.clickable-title[data-v-14e257e5]:hover{color:#10b981}.skill-name[data-v-14e257e5]{color:#6b7280;font-size:11px;font-weight:500;font-family:SF Mono,Monaco,Menlo,Ubuntu Mono,monospace;background:#f3f4f6;border:1px solid #d1d5db;border-radius:8px;padding:4px 10px;display:inline-block;white-space:nowrap}.skill-description[data-v-14e257e5]{color:#6b7280;font-size:14px;line-height:1.5;margin-bottom:12px}.skill-actions[data-v-14e257e5]{padding:0 20px 20px;display:flex;gap:12px}.skill-actions .n-button[data-v-14e257e5]{flex:1}.loading[data-v-14e257e5],.empty[data-v-14e257e5]{display:flex;justify-content:center;align-items:center;min-height:300px}@media(max-width:768px){.skills-grid[data-v-14e257e5]{grid-template-columns:1fr;gap:16px}}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{d as k,o as m,A as B,J as h,P as N,j as e,t,B as l,C as a,av as T,Q as R,g as x,aw as u,ax as o,ay as n}from"./index-CBewG1aH.js";import{getCount as c,getLocalJobCount as C}from"./common-CaS8RUp0.js";import{_ as D}from"./_plugin-vue_export-helper-DlAUqK2U.js";const Q={class:"dashboard-page"},y={class:"page-header"},A={class:"page-title"},S=k({__name:"Dashboard",setup(L){const s=R({agents:0,nodes:0,taskQueue:0,scheduledTasks:0,knowledgeBase:0,note:0,event:0,todo:0,file:0}),w=async()=>{try{const d=await c("Local Ai Agent");d.success&&(s.agents=d.count||0);const i=await c("Local Ai Node");i.success&&(s.nodes=i.count||0);const f=await C();f.success&&(s.taskQueue=f.count||0);const r=await c("Local Scheduled Job");r.success&&(s.scheduledTasks=r.count||0);const _=await c("Knowledge Base");_.success&&(s.knowledgeBase=_.count||0);const v=await c("Note");v.success&&(s.note=v.count||0);const b=await c("Event");b.success&&(s.event=b.count||0);const g=await c("ToDo");g.success&&(s.todo=g.count||0);const p=await c("File");p.success&&(s.file=p.count||0)}catch(d){console.error("加载统计数据失败:",d)}};return m(()=>{w()}),(d,i)=>(x(),B("div",Q,[h("div",y,[h("h1",A,N(e(t)("Dashboard")),1)]),l(e(T),{cols:4,"x-gap":16,"y-gap":16,responsive:"screen","item-responsive":!0,class:"stats-grid"},{default:a(()=>[l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Total Agents"),value:s.agents},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Total Nodes"),value:s.nodes},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Task Queue"),value:s.taskQueue},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Scheduled Tasks"),value:s.scheduledTasks},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Knowledge Base"),value:s.knowledgeBase},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Note"),value:s.note},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Event"),value:s.event},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("ToDo"),value:s.todo},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("File"),value:s.file},null,8,["label","value"])]),_:1})]),_:1})]),_:1})]))}}),G=D(S,[["__scopeId","data-v-d1f0aa95"]]);export{G as default};
|
||||
import{d as k,o as m,A as B,J as h,P as N,j as e,t,B as l,C as a,av as T,Q as R,g as x,aw as u,ax as o,ay as n}from"./index-CBewG1aH.js";import{getCount as c,getLocalJobCount as C}from"./common-CaS8RUp0.js";import{_ as D}from"./_plugin-vue_export-helper-DlAUqK2U.js";const Q={class:"dashboard-page"},y={class:"page-header"},A={class:"page-title"},S=k({__name:"Dashboard",setup(L){const s=R({skills:0,nodes:0,taskQueue:0,scheduledTasks:0,knowledgeBase:0,note:0,event:0,todo:0,file:0}),w=async()=>{try{const d=await c("Local Ai Agent");d.success&&(s.skills=d.count||0);const i=await c("Local Ai Node");i.success&&(s.nodes=i.count||0);const f=await C();f.success&&(s.taskQueue=f.count||0);const r=await c("Local Scheduled Job");r.success&&(s.scheduledTasks=r.count||0);const _=await c("Knowledge Base");_.success&&(s.knowledgeBase=_.count||0);const v=await c("Note");v.success&&(s.note=v.count||0);const b=await c("Event");b.success&&(s.event=b.count||0);const g=await c("ToDo");g.success&&(s.todo=g.count||0);const p=await c("File");p.success&&(s.file=p.count||0)}catch(d){console.error("加载统计数据失败:",d)}};return m(()=>{w()}),(d,i)=>(x(),B("div",Q,[h("div",y,[h("h1",A,N(e(t)("Dashboard")),1)]),l(e(T),{cols:4,"x-gap":16,"y-gap":16,responsive:"screen","item-responsive":!0,class:"stats-grid"},{default:a(()=>[l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Total Agents"),value:s.skills},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Total Nodes"),value:s.nodes},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Task Queue"),value:s.taskQueue},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Scheduled Tasks"),value:s.scheduledTasks},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Knowledge Base"),value:s.knowledgeBase},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Note"),value:s.note},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("Event"),value:s.event},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("ToDo"),value:s.todo},null,8,["label","value"])]),_:1})]),_:1}),l(e(u),null,{default:a(()=>[l(e(o),null,{default:a(()=>[l(e(n),{label:e(t)("File"),value:s.file},null,8,["label","value"])]),_:1})]),_:1})]),_:1})]))}}),G=D(S,[["__scopeId","data-v-d1f0aa95"]]);export{G as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
import{d as h,a0 as F,o as A,A as _,J as p,P as d,j as s,t as a,B as S,C as k,as as q,i as x,b as C,c as g,g as m,_ as D,e as N,aD as P}from"./index-CBewG1aH.js";import{u as T,F as V}from"./FlowBuilderContainer-DsK2pBHP.js";import{useFlowBuilderStore as b}from"./flowBuilder-CXOkXb8n.js";import{_ as I}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./iconify-gC035N5m.js";import"./AIAgentFlowBuilder-hFRPYtmD.js";import"./vue-flow-core-B32lO9yC.js";import"./nodeMetadata-CLrm-0CB.js";import"./common-CaS8RUp0.js";import"./NodePropertyModal-DutSkaSe.js";import"./SchemaFormRenderer-BoLivC3r.js";import"./nodes-B80fFdtY.js";import"./NodePalette-B_CHerrO.js";import"./ExecutionResults-CMv5OhfQ.js";const J={class:"flow-builder-page"},M={key:0,class:"empty-state"},R={class:"empty-content"},j=h({__name:"FlowBuilder",setup(E){const y=N(),o=C(),i=F(),c=T(),t=b(),r=g(()=>o.query.id||o.query.name||t.getAgentId()),f=g(()=>{const e=o.query.pagetype;return e?P(e):""}),w=g(()=>r.value||t.hasFlowData());A(async()=>{const e=o.query.id||o.query.name,n=f.value;if(e&&!t.getAgentId())try{await c.fetchAgent(e,n);const l=c.currentAgent;if(l?.skill_flow){let u=l.skill_flow;typeof u=="string"&&(u=JSON.parse(u)),t.activateFlowBuilder(u,e)}}catch(l){console.error("恢复智能体数据失败:",l)}});const v=async e=>{try{r.value?(await c.updateAgent(r.value,{skill_flow:e},f.value),i.success(a("Agent flow saved successfully")),t.deactivateFlowBuilder()):i.success(a("Flow saved successfully"))}catch(n){i.error(a("Save failed")+": "+(n?.message||""))}},B=()=>{y.push("/agents")};return(e,n)=>(m(),_("div",J,[w.value?(m(),x(V,{key:1,"initial-value":s(t).getFlowData(),"skill-id":r.value,onSave:v},null,8,["initial-value","skill-id"])):(m(),_("div",M,[p("div",R,[p("h3",null,d(s(a)("Flow Builder")),1),p("p",null,d(s(a)("Please enter from Agents page to open Flow Builder")),1),S(s(q),{type:"primary",onClick:B},{default:k(()=>[D(d(s(a)("View Agents")),1)]),_:1})])]))]))}}),te=I(j,[["__scopeId","data-v-bffeb9f8"]]);export{te as default};
|
||||
import{d as h,a0 as F,o as A,A as _,J as p,P as d,j as s,t as a,B as S,C as k,as as q,i as x,b as C,c as g,g as m,_ as D,e as N,aD as P}from"./index-CBewG1aH.js";import{u as T,F as V}from"./FlowBuilderContainer-DsK2pBHP.js";import{useFlowBuilderStore as b}from"./flowBuilder-CXOkXb8n.js";import{_ as I}from"./_plugin-vue_export-helper-DlAUqK2U.js";import"./iconify-gC035N5m.js";import"./AIAgentFlowBuilder-hFRPYtmD.js";import"./vue-flow-core-B32lO9yC.js";import"./nodeMetadata-CLrm-0CB.js";import"./common-CaS8RUp0.js";import"./NodePropertyModal-DutSkaSe.js";import"./SchemaFormRenderer-BoLivC3r.js";import"./nodes-B80fFdtY.js";import"./NodePalette-B_CHerrO.js";import"./ExecutionResults-CMv5OhfQ.js";const J={class:"flow-builder-page"},M={key:0,class:"empty-state"},R={class:"empty-content"},j=h({__name:"FlowBuilder",setup(E){const y=N(),o=C(),i=F(),c=T(),t=b(),r=g(()=>o.query.id||o.query.name||t.getAgentId()),f=g(()=>{const e=o.query.pagetype;return e?P(e):""}),w=g(()=>r.value||t.hasFlowData());A(async()=>{const e=o.query.id||o.query.name,n=f.value;if(e&&!t.getAgentId())try{await c.fetchAgent(e,n);const l=c.currentAgent;if(l?.skill_flow){let u=l.skill_flow;typeof u=="string"&&(u=JSON.parse(u)),t.activateFlowBuilder(u,e)}}catch(l){console.error("恢复智能体数据失败:",l)}});const v=async e=>{try{r.value?(await c.updateAgent(r.value,{skill_flow:e},f.value),i.success(a("Agent flow saved successfully")),t.deactivateFlowBuilder()):i.success(a("Flow saved successfully"))}catch(n){i.error(a("Save failed")+": "+(n?.message||""))}},B=()=>{y.push("/skills")};return(e,n)=>(m(),_("div",J,[w.value?(m(),x(V,{key:1,"initial-value":s(t).getFlowData(),"skill-id":r.value,onSave:v},null,8,["initial-value","skill-id"])):(m(),_("div",M,[p("div",R,[p("h3",null,d(s(a)("Flow Builder")),1),p("p",null,d(s(a)("Please enter from Agents page to open Flow Builder")),1),S(s(q),{type:"primary",onClick:B},{default:k(()=>[D(d(s(a)("View Agents")),1)]),_:1})])]))]))}}),te=I(j,[["__scopeId","data-v-bffeb9f8"]]);export{te as default};
|
||||
|
||||
@ -1 +1 @@
|
||||
import{y as V,r as _,d as E,a0 as N,w as R,A as j,J as w,P as A,B as c,C as d,j as n,aB as x,c as m,g as T,as as B,_ as I,t as u,aC as b,e as z,aD as O}from"./index-CBewG1aH.js";import{I as F}from"./iconify-gC035N5m.js";import P from"./AIAgentFlowBuilder-hFRPYtmD.js";import{useFlowBuilderStore as q}from"./flowBuilder-CXOkXb8n.js";import{getRecord as M,updateRecord as $}from"./common-CaS8RUp0.js";import{_ as J}from"./_plugin-vue_export-helper-DlAUqK2U.js";const G=async(a,l)=>{try{const e=await M(l,a);if(!e.success)throw new Error(e.message||"获取AI Agent详情失败");return e.data}catch(e){throw new Error(e.message||"获取AI Agent详情失败")}},H=async(a,l,e)=>{try{const o=await $(e,a,l);if(!o.success)throw new Error(o.message||"更新AI Agent失败");return o.data}catch(o){throw console.error("Error in updateAgentApi:",o),new Error(o.message||"更新AI Agent失败")}},K=V("agent",()=>{const a=_(null),l=_("");return{currentAgent:a,currentPageType:l,fetchAgent:async(i,s)=>{try{const r=await G(i,s);a.value=r,l.value=s}catch(r){throw console.error("获取AI Agent详情失败:",r),r}},updateAgent:async(i,s,r)=>{try{return await H(i,s,r),a.value&&a.value.name===i&&(a.value={...a.value,...s}),{success:!0}}catch(g){throw console.error("更新AI Agent失败:",g),g}}}}),L={class:"flow-builder"},Q={class:"flow-builder-header"},U={class:"header-left"},W={class:"title"},X={class:"header-right"},Y={class:"flow-builder-content"},Z=E({__name:"FlowBuilderContainer",props:{initialValue:{},skillId:{}},emits:["save"],setup(a,{emit:l}){const e=a,o=l,i=z(),s=N(),r=K(),g=q(),f=_(""),S=m(()=>{if(e.initialValue&&Object.keys(e.initialValue).length>0)return e.initialValue;const t=g.getFlowData();return t&&Object.keys(t).length>0?t:{}}),h=_(),p=m(()=>e.skillId||g.getAgentId()),y=m(()=>{const v=i.currentRoute.value.query.pagetype;return v?O(v):""}),k=m(()=>f.value?`${f.value}`:u("Flow Builder"));R(p,async t=>{if(t)try{await r.fetchAgent(t,y.value),f.value=r.currentAgent?.skill_name||r.currentAgent?.name||""}catch(v){console.error("获取智能体信息失败:",v),f.value=""}else f.value=""},{immediate:!0});const C=async()=>{try{if(!h.value){s.error(u("Flow Builder is not initialized"));return}const t=h.value.getFlowData();p.value?(await r.updateAgent(p.value,{skill_flow:t},y.value),s.success(u("Flow saved successfully"))):(o("save",t),s.success(u("Flow saved successfully")))}catch(t){s.error(u("Save failed")+": "+(t.message||u("An error occurred during save")))}},D=()=>{g.deactivateFlowBuilder(),i.back()};return(t,v)=>(T(),j("div",L,[w("div",Q,[w("div",U,[w("h2",W,A(k.value),1)]),w("div",X,[c(n(x),null,{default:d(()=>[c(n(B),{size:"small",onClick:D},{icon:d(()=>[c(n(b),null,{default:d(()=>[c(n(F),{icon:"tabler:arrow-left"})]),_:1})]),default:d(()=>[I(" "+A(n(u)("Back")),1)]),_:1}),c(n(B),{size:"small",type:"primary",onClick:C,class:"save-btn-brand"},{icon:d(()=>[c(n(b),null,{default:d(()=>[c(n(F),{icon:"tabler:check"})]),_:1})]),default:d(()=>[I(" "+A(n(u)("Save")),1)]),_:1})]),_:1})])]),w("div",Y,[c(P,{ref_key:"flowBuilderRef",ref:h,"initial-value":S.value,"skill-id":p.value},null,8,["initial-value","skill-id"])])]))}}),ee=J(Z,[["__scopeId","data-v-c9b4f7b6"]]),le=Object.freeze(Object.defineProperty({__proto__:null,default:ee},Symbol.toStringTag,{value:"Module"}));export{ee as F,le as a,K as u};
|
||||
import{y as V,r as _,d as E,a0 as N,w as R,A as j,J as w,P as A,B as c,C as d,j as n,aB as x,c as m,g as T,as as B,_ as I,t as u,aC as b,e as z,aD as O}from"./index-CBewG1aH.js";import{I as F}from"./iconify-gC035N5m.js";import P from"./AIAgentFlowBuilder-hFRPYtmD.js";import{useFlowBuilderStore as q}from"./flowBuilder-CXOkXb8n.js";import{getRecord as M,updateRecord as $}from"./common-CaS8RUp0.js";import{_ as J}from"./_plugin-vue_export-helper-DlAUqK2U.js";const G=async(a,l)=>{try{const e=await M(l,a);if(!e.success)throw new Error(e.message||"获取AI Agent详情失败");return e.data}catch(e){throw new Error(e.message||"获取AI Agent详情失败")}},H=async(a,l,e)=>{try{const o=await $(e,a,l);if(!o.success)throw new Error(o.message||"更新AI Agent失败");return o.data}catch(o){throw console.error("Error in updateAgentApi:",o),new Error(o.message||"更新AI Agent失败")}},K=V("skill",()=>{const a=_(null),l=_("");return{currentAgent:a,currentPageType:l,fetchAgent:async(i,s)=>{try{const r=await G(i,s);a.value=r,l.value=s}catch(r){throw console.error("获取AI Agent详情失败:",r),r}},updateAgent:async(i,s,r)=>{try{return await H(i,s,r),a.value&&a.value.name===i&&(a.value={...a.value,...s}),{success:!0}}catch(g){throw console.error("更新AI Agent失败:",g),g}}}}),L={class:"flow-builder"},Q={class:"flow-builder-header"},U={class:"header-left"},W={class:"title"},X={class:"header-right"},Y={class:"flow-builder-content"},Z=E({__name:"FlowBuilderContainer",props:{initialValue:{},skillId:{}},emits:["save"],setup(a,{emit:l}){const e=a,o=l,i=z(),s=N(),r=K(),g=q(),f=_(""),S=m(()=>{if(e.initialValue&&Object.keys(e.initialValue).length>0)return e.initialValue;const t=g.getFlowData();return t&&Object.keys(t).length>0?t:{}}),h=_(),p=m(()=>e.skillId||g.getAgentId()),y=m(()=>{const v=i.currentRoute.value.query.pagetype;return v?O(v):""}),k=m(()=>f.value?`${f.value}`:u("Flow Builder"));R(p,async t=>{if(t)try{await r.fetchAgent(t,y.value),f.value=r.currentAgent?.skill_name||r.currentAgent?.name||""}catch(v){console.error("获取智能体信息失败:",v),f.value=""}else f.value=""},{immediate:!0});const C=async()=>{try{if(!h.value){s.error(u("Flow Builder is not initialized"));return}const t=h.value.getFlowData();p.value?(await r.updateAgent(p.value,{skill_flow:t},y.value),s.success(u("Flow saved successfully"))):(o("save",t),s.success(u("Flow saved successfully")))}catch(t){s.error(u("Save failed")+": "+(t.message||u("An error occurred during save")))}},D=()=>{g.deactivateFlowBuilder(),i.back()};return(t,v)=>(T(),j("div",L,[w("div",Q,[w("div",U,[w("h2",W,A(k.value),1)]),w("div",X,[c(n(x),null,{default:d(()=>[c(n(B),{size:"small",onClick:D},{icon:d(()=>[c(n(b),null,{default:d(()=>[c(n(F),{icon:"tabler:arrow-left"})]),_:1})]),default:d(()=>[I(" "+A(n(u)("Back")),1)]),_:1}),c(n(B),{size:"small",type:"primary",onClick:C,class:"save-btn-brand"},{icon:d(()=>[c(n(b),null,{default:d(()=>[c(n(F),{icon:"tabler:check"})]),_:1})]),default:d(()=>[I(" "+A(n(u)("Save")),1)]),_:1})]),_:1})])]),w("div",Y,[c(P,{ref_key:"flowBuilderRef",ref:h,"initial-value":S.value,"skill-id":p.value},null,8,["initial-value","skill-id"])])]))}}),ee=J(Z,[["__scopeId","data-v-c9b4f7b6"]]),le=Object.freeze(Object.defineProperty({__proto__:null,default:ee},Symbol.toStringTag,{value:"Module"}));export{ee as F,le as a,K as u};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/flowBuilder-CXOkXb8n.js","assets/index-CBewG1aH.js","assets/index-Cl-AM8AM.css"])))=>i.map(i=>d[i]);
|
||||
import{d as g,a0 as p,g as y,A as b,J as a,af as l,H as u,c as v,r as B,a as C,aN as E,a2 as F}from"./index-CBewG1aH.js";import{api as S}from"./common-CaS8RUp0.js";import{_}from"./_plugin-vue_export-helper-DlAUqK2U.js";const k=["title"],M=["title"],N=["title","disabled"],R=["title"],$=["title"],D=g({__name:"ai_skill_list_actions",props:{context:{}},setup(n){const e=n,f=v(()=>(e.context.viewMode||"list")==="card"?"actions-container card-actions":"actions-container col-actions"),r=p(),c=B(!1);async function x(){try{c.value=!0;const o=e.context.row.name;if(!o){r.error(e.context.t("Agent name is required"));return}const t=await S.call("jingrow.ai.pagetype.ai_skill.ai_skill.execute_agent_by_name",{skill_name:o}),i=t?.message||t;i?.success?r.success(e.context.t("Submitted successfully")):r.error(i?.error||e.context.t("Execution failed"))}catch(o){r.error(o?.message||e.context.t("Execution failed"))}finally{c.value=!1}}async function w(){try{const o=e.context.row.name;let t={};if(e.context.row.skill_flow!==void 0&&e.context.row.skill_flow!==null){const s=e.context.row.skill_flow;if(t=s,typeof s=="string")try{t=JSON.parse(s)}catch{t={}}}else try{const d=((await C.get(`/api/data/${encodeURIComponent(e.context.entity)}/${encodeURIComponent(o)}`)).data?.data||{}).skill_flow??{};if(t=d,typeof d=="string")try{t=JSON.parse(d)}catch{t={}}}catch(s){console.error("获取智能体数据失败:",s),r.error(e.context.t("Failed to load agent data"));return}const i=E(e.context.entity),{useFlowBuilderStore:m}=await F(async()=>{const{useFlowBuilderStore:s}=await import("./flowBuilder-CXOkXb8n.js");return{useFlowBuilderStore:s}},__vite__mapDeps([0,1,2]));m().activateFlowBuilder(t,o),e.context.router.push({name:"FlowBuilder",query:{pagetype:i,id:o}})}catch(o){console.error("打开流程编排失败:",o),r.error(o?.message||e.context.t("Failed to open flow builder"))}}return(o,t)=>(y(),b("div",{class:u(f.value)},[a("button",{class:"action-btn",onClick:t[0]||(t[0]=l(i=>n.context.openDetail(n.context.row.name),["stop"])),title:n.context.t("View")},[...t[3]||(t[3]=[a("i",{class:"fa fa-eye"},null,-1)])],8,k),a("button",{class:"action-btn",onClick:t[1]||(t[1]=l(i=>n.context.editRecord(n.context.row),["stop"])),title:n.context.t("Edit")},[...t[4]||(t[4]=[a("i",{class:"fa fa-edit"},null,-1)])],8,M),a("button",{class:"action-btn execute-btn",onClick:l(x,["stop"]),title:n.context.t("Execute"),disabled:c.value},[a("i",{class:u(c.value?"fa fa-spinner fa-spin":"fa fa-play")},null,2)],8,N),a("button",{class:"action-btn flow-builder-btn",onClick:l(w,["stop"]),title:n.context.t("Flow Builder")},[...t[5]||(t[5]=[a("i",{class:"fa fa-sitemap"},null,-1)])],8,R),a("button",{class:"action-btn delete-btn",onClick:t[2]||(t[2]=l(i=>n.context.deleteRecord(n.context.row.name),["stop"])),title:n.context.t("Delete")},[...t[6]||(t[6]=[a("i",{class:"fa fa-trash"},null,-1)])],8,$)],2))}}),V=_(D,[["__scopeId","data-v-1aa3dda6"]]);export{V as default};
|
||||
import{d as g,a0 as p,g as y,A as b,J as a,af as l,H as u,c as v,r as B,a as C,aN as E,a2 as F}from"./index-CBewG1aH.js";import{api as S}from"./common-CaS8RUp0.js";import{_}from"./_plugin-vue_export-helper-DlAUqK2U.js";const k=["title"],M=["title"],N=["title","disabled"],R=["title"],$=["title"],D=g({__name:"ai_skill_list_actions",props:{context:{}},setup(n){const e=n,f=v(()=>(e.context.viewMode||"list")==="card"?"actions-container card-actions":"actions-container col-actions"),r=p(),c=B(!1);async function x(){try{c.value=!0;const o=e.context.row.name;if(!o){r.error(e.context.t("Agent name is required"));return}const t=await S.call("jingrow.ai.pagetype.ai_skill.ai_skill.execute_skill_by_name",{skill_name:o}),i=t?.message||t;i?.success?r.success(e.context.t("Submitted successfully")):r.error(i?.error||e.context.t("Execution failed"))}catch(o){r.error(o?.message||e.context.t("Execution failed"))}finally{c.value=!1}}async function w(){try{const o=e.context.row.name;let t={};if(e.context.row.skill_flow!==void 0&&e.context.row.skill_flow!==null){const s=e.context.row.skill_flow;if(t=s,typeof s=="string")try{t=JSON.parse(s)}catch{t={}}}else try{const d=((await C.get(`/api/data/${encodeURIComponent(e.context.entity)}/${encodeURIComponent(o)}`)).data?.data||{}).skill_flow??{};if(t=d,typeof d=="string")try{t=JSON.parse(d)}catch{t={}}}catch(s){console.error("获取智能体数据失败:",s),r.error(e.context.t("Failed to load skill data"));return}const i=E(e.context.entity),{useFlowBuilderStore:m}=await F(async()=>{const{useFlowBuilderStore:s}=await import("./flowBuilder-CXOkXb8n.js");return{useFlowBuilderStore:s}},__vite__mapDeps([0,1,2]));m().activateFlowBuilder(t,o),e.context.router.push({name:"FlowBuilder",query:{pagetype:i,id:o}})}catch(o){console.error("打开流程编排失败:",o),r.error(o?.message||e.context.t("Failed to open flow builder"))}}return(o,t)=>(y(),b("div",{class:u(f.value)},[a("button",{class:"action-btn",onClick:t[0]||(t[0]=l(i=>n.context.openDetail(n.context.row.name),["stop"])),title:n.context.t("View")},[...t[3]||(t[3]=[a("i",{class:"fa fa-eye"},null,-1)])],8,k),a("button",{class:"action-btn",onClick:t[1]||(t[1]=l(i=>n.context.editRecord(n.context.row),["stop"])),title:n.context.t("Edit")},[...t[4]||(t[4]=[a("i",{class:"fa fa-edit"},null,-1)])],8,M),a("button",{class:"action-btn execute-btn",onClick:l(x,["stop"]),title:n.context.t("Execute"),disabled:c.value},[a("i",{class:u(c.value?"fa fa-spinner fa-spin":"fa fa-play")},null,2)],8,N),a("button",{class:"action-btn flow-builder-btn",onClick:l(w,["stop"]),title:n.context.t("Flow Builder")},[...t[5]||(t[5]=[a("i",{class:"fa fa-sitemap"},null,-1)])],8,R),a("button",{class:"action-btn delete-btn",onClick:t[2]||(t[2]=l(i=>n.context.deleteRecord(n.context.row.name),["stop"])),title:n.context.t("Delete")},[...t[6]||(t[6]=[a("i",{class:"fa fa-trash"},null,-1)])],8,$)],2))}}),V=_(D,[["__scopeId","data-v-1aa3dda6"]]);export{V as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/flowBuilder-CXOkXb8n.js","assets/index-CBewG1aH.js","assets/index-Cl-AM8AM.css"])))=>i.map(i=>d[i]);
|
||||
import{d as g,a0 as p,g as y,A as b,J as a,af as c,H as u,c as v,r as B,a as C,aN as E,a2 as F}from"./index-CBewG1aH.js";import{api as S}from"./common-CaS8RUp0.js";import{_ as k}from"./_plugin-vue_export-helper-DlAUqK2U.js";const _=["title"],M=["title"],N=["title","disabled"],R=["title"],$=["title"],D=g({__name:"local_ai_skill_list_actions",props:{context:{}},setup(n){const e=n,f=v(()=>(e.context.viewMode||"list")==="card"?"actions-container card-actions":"actions-container col-actions"),i=p(),r=B(!1);async function x(){try{r.value=!0;const o=e.context.row.name;if(!o){i.error(e.context.t("Agent name is required"));return}const t=await S.call("jingrow.ai.utils.jlocal.execute_local_ai_skill",{name:o}),l=t?.message||t;l?.success?i.success(e.context.t("Submitted successfully")):i.error(l?.error||e.context.t("Execution failed"))}catch(o){i.error(o?.message||e.context.t("Execution failed"))}finally{r.value=!1}}async function w(){try{const o=e.context.row.name;let t={};if(e.context.row.skill_flow!==void 0&&e.context.row.skill_flow!==null){const s=e.context.row.skill_flow;if(t=s,typeof s=="string")try{t=JSON.parse(s)}catch{t={}}}else try{const d=((await C.get(`/api/data/${encodeURIComponent(e.context.entity)}/${encodeURIComponent(o)}`)).data?.data||{}).skill_flow??{};if(t=d,typeof d=="string")try{t=JSON.parse(d)}catch{t={}}}catch(s){console.error("获取智能体数据失败:",s),i.error(e.context.t("Failed to load agent data"));return}const l=E(e.context.entity),{useFlowBuilderStore:m}=await F(async()=>{const{useFlowBuilderStore:s}=await import("./flowBuilder-CXOkXb8n.js");return{useFlowBuilderStore:s}},__vite__mapDeps([0,1,2]));m().activateFlowBuilder(t,o),e.context.router.push({name:"FlowBuilder",query:{pagetype:l,id:o}})}catch(o){console.error("打开流程编排失败:",o),i.error(o?.message||e.context.t("Failed to open flow builder"))}}return(o,t)=>(y(),b("div",{class:u(f.value)},[a("button",{class:"action-btn",onClick:t[0]||(t[0]=c(l=>n.context.openDetail(n.context.row.name),["stop"])),title:n.context.t("View")},[...t[3]||(t[3]=[a("i",{class:"fa fa-eye"},null,-1)])],8,_),a("button",{class:"action-btn",onClick:t[1]||(t[1]=c(l=>n.context.editRecord(n.context.row),["stop"])),title:n.context.t("Edit")},[...t[4]||(t[4]=[a("i",{class:"fa fa-edit"},null,-1)])],8,M),a("button",{class:"action-btn execute-btn",onClick:c(x,["stop"]),title:n.context.t("Execute"),disabled:r.value},[a("i",{class:u(r.value?"fa fa-spinner fa-spin":"fa fa-play")},null,2)],8,N),a("button",{class:"action-btn flow-builder-btn",onClick:c(w,["stop"]),title:n.context.t("Flow Builder")},[...t[5]||(t[5]=[a("i",{class:"fa fa-sitemap"},null,-1)])],8,R),a("button",{class:"action-btn delete-btn",onClick:t[2]||(t[2]=c(l=>n.context.deleteRecord(n.context.row.name),["stop"])),title:n.context.t("Delete")},[...t[6]||(t[6]=[a("i",{class:"fa fa-trash"},null,-1)])],8,$)],2))}}),V=k(D,[["__scopeId","data-v-f2238862"]]);export{V as default};
|
||||
import{d as g,a0 as p,g as y,A as b,J as a,af as c,H as u,c as v,r as B,a as C,aN as E,a2 as F}from"./index-CBewG1aH.js";import{api as S}from"./common-CaS8RUp0.js";import{_ as k}from"./_plugin-vue_export-helper-DlAUqK2U.js";const _=["title"],M=["title"],N=["title","disabled"],R=["title"],$=["title"],D=g({__name:"local_ai_skill_list_actions",props:{context:{}},setup(n){const e=n,f=v(()=>(e.context.viewMode||"list")==="card"?"actions-container card-actions":"actions-container col-actions"),i=p(),r=B(!1);async function x(){try{r.value=!0;const o=e.context.row.name;if(!o){i.error(e.context.t("Agent name is required"));return}const t=await S.call("jingrow.ai.utils.jlocal.execute_local_ai_skill",{name:o}),l=t?.message||t;l?.success?i.success(e.context.t("Submitted successfully")):i.error(l?.error||e.context.t("Execution failed"))}catch(o){i.error(o?.message||e.context.t("Execution failed"))}finally{r.value=!1}}async function w(){try{const o=e.context.row.name;let t={};if(e.context.row.skill_flow!==void 0&&e.context.row.skill_flow!==null){const s=e.context.row.skill_flow;if(t=s,typeof s=="string")try{t=JSON.parse(s)}catch{t={}}}else try{const d=((await C.get(`/api/data/${encodeURIComponent(e.context.entity)}/${encodeURIComponent(o)}`)).data?.data||{}).skill_flow??{};if(t=d,typeof d=="string")try{t=JSON.parse(d)}catch{t={}}}catch(s){console.error("获取智能体数据失败:",s),i.error(e.context.t("Failed to load skill data"));return}const l=E(e.context.entity),{useFlowBuilderStore:m}=await F(async()=>{const{useFlowBuilderStore:s}=await import("./flowBuilder-CXOkXb8n.js");return{useFlowBuilderStore:s}},__vite__mapDeps([0,1,2]));m().activateFlowBuilder(t,o),e.context.router.push({name:"FlowBuilder",query:{pagetype:l,id:o}})}catch(o){console.error("打开流程编排失败:",o),i.error(o?.message||e.context.t("Failed to open flow builder"))}}return(o,t)=>(y(),b("div",{class:u(f.value)},[a("button",{class:"action-btn",onClick:t[0]||(t[0]=c(l=>n.context.openDetail(n.context.row.name),["stop"])),title:n.context.t("View")},[...t[3]||(t[3]=[a("i",{class:"fa fa-eye"},null,-1)])],8,_),a("button",{class:"action-btn",onClick:t[1]||(t[1]=c(l=>n.context.editRecord(n.context.row),["stop"])),title:n.context.t("Edit")},[...t[4]||(t[4]=[a("i",{class:"fa fa-edit"},null,-1)])],8,M),a("button",{class:"action-btn execute-btn",onClick:c(x,["stop"]),title:n.context.t("Execute"),disabled:r.value},[a("i",{class:u(r.value?"fa fa-spinner fa-spin":"fa fa-play")},null,2)],8,N),a("button",{class:"action-btn flow-builder-btn",onClick:c(w,["stop"]),title:n.context.t("Flow Builder")},[...t[5]||(t[5]=[a("i",{class:"fa fa-sitemap"},null,-1)])],8,R),a("button",{class:"action-btn delete-btn",onClick:t[2]||(t[2]=c(l=>n.context.deleteRecord(n.context.row.name),["stop"])),title:n.context.t("Delete")},[...t[6]||(t[6]=[a("i",{class:"fa fa-trash"},null,-1)])],8,$)],2))}}),V=k(D,[["__scopeId","data-v-f2238862"]]);export{V as default};
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -632,8 +632,8 @@
|
||||
</filter>
|
||||
</defs>
|
||||
</symbol>
|
||||
<symbol id="es-line-agent" fill="none" viewBox="0 0 16 16">
|
||||
<g class="es-line-agent" filter="url(#a)">
|
||||
<symbol id="es-line-skill" fill="none" viewBox="0 0 16 16">
|
||||
<g class="es-line-skill" filter="url(#a)">
|
||||
<path fill="var(--icon-stroke)" fill-rule="evenodd" d="M9.625 4.49a1.625 1.625 0 1 1-3.25 0 1.625 1.625 0 0 1 3.25 0Zm1 0a2.625 2.625 0 1 1-5.25 0 2.625 2.625 0 0 1 5.25 0Zm-7.294 6.996a3.347 3.347 0 0 1 3.267-2.621h2.805a3.347 3.347 0 0 1 3.267 2.62l.093.418a1.424 1.424 0 0 1-1.39 1.732H4.628a1.423 1.423 0 0 1-1.39-1.732l.093-.417Zm3.267-3.621a4.347 4.347 0 0 0-4.243 3.404l-.093.417a2.424 2.424 0 0 0 2.366 2.95h6.745a2.424 2.424 0 0 0 2.366-2.95l-.093-.417a4.347 4.347 0 0 0-4.243-3.404H6.598Z" class="Union" clip-rule="evenodd"/>
|
||||
</g>
|
||||
<defs>
|
||||
@ -1468,8 +1468,8 @@
|
||||
<path fill="var(--icon-stroke)" fill-rule="evenodd" d="M1 8a7 7 0 1 1 14 0A7 7 0 0 1 1 8Zm6.13 2.684 3.387-2.237a.521.521 0 0 0 .26-.447.521.521 0 0 0-.26-.447L7.131 5.316a.67.67 0 0 0-.645-.06.623.623 0 0 0-.375.507v4.474a.623.623 0 0 0 .375.507.67.67 0 0 0 .645-.06Z" class="Union" clip-rule="evenodd"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="es-solid-agent" viewBox="0 0 16 16">
|
||||
<g class="es-solid-agent" filter="url(#a)">
|
||||
<symbol id="es-solid-skill" viewBox="0 0 16 16">
|
||||
<g class="es-solid-skill" filter="url(#a)">
|
||||
<path fill="var(--icon-stroke)" fill-rule="evenodd" d="M8 7.115a2.625 2.625 0 1 0 0-5.25 2.625 2.625 0 0 0 0 5.25Zm-1.402.75a4.347 4.347 0 0 0-4.243 3.404l-.093.417a2.424 2.424 0 0 0 2.366 2.95h6.745a2.424 2.424 0 0 0 2.366-2.95l-.093-.417a4.347 4.347 0 0 0-4.243-3.404h-.319L8 10.184l-1.084-2.32h-.318Z" class="Union" clip-rule="evenodd"/>
|
||||
</g>
|
||||
<defs>
|
||||
@ -1520,8 +1520,8 @@
|
||||
<path fill="var(--icon-stroke)" fill-rule="evenodd" d="M5 2.623V3.95a.5.5 0 0 0 1 0V2.623h7.502a1.5 1.5 0 0 1 1.5 1.5V5.91a.5.5 0 0 1-.4.49 1.669 1.669 0 0 0 0 3.268.5.5 0 0 1 .4.49v1.719a1.5 1.5 0 0 1-1.5 1.5H6V12.05a.5.5 0 1 0-1 0v1.327H2.498a1.5 1.5 0 0 1-1.5-1.5v-1.719a.5.5 0 0 1 .4-.49 1.669 1.669 0 0 0 0-3.268.5.5 0 0 1-.4-.49V4.123a1.5 1.5 0 0 1 1.5-1.5H5ZM6 6.65a.5.5 0 1 0-1 0v2.7a.5.5 0 0 0 1 0v-2.7Z" class="Subtract" clip-rule="evenodd"/>
|
||||
</g>
|
||||
</symbol>
|
||||
<symbol id="es-solid-agent" viewBox="0 0 16 16">
|
||||
<g class="es-solid-agent" filter="url(#a)">
|
||||
<symbol id="es-solid-skill" viewBox="0 0 16 16">
|
||||
<g class="es-solid-skill" filter="url(#a)">
|
||||
<path fill="var(--icon-stroke)" fill-rule="evenodd" d="M8 7.115a2.625 2.625 0 1 0 0-5.25 2.625 2.625 0 0 0 0 5.25Zm-5.645 4.154a4.347 4.347 0 0 1 4.243-3.404h2.805a4.347 4.347 0 0 1 4.243 3.404l.093.417a2.424 2.424 0 0 1-2.366 2.95H4.628a2.424 2.424 0 0 1-2.366-2.95l.093-.417Z" class="Union" clip-rule="evenodd"/>
|
||||
</g>
|
||||
<defs>
|
||||
|
||||
|
Before Width: | Height: | Size: 198 KiB After Width: | Height: | Size: 198 KiB |
@ -17,12 +17,12 @@ class AiSkillFlowBuilder {
|
||||
|
||||
init() {
|
||||
// 设置全局智能体信息,供执行器使用
|
||||
this.setup_global_agent_info();
|
||||
this.setup_global_skill_info();
|
||||
this.setup_app();
|
||||
this.watch_changes();
|
||||
}
|
||||
|
||||
setup_global_agent_info() {
|
||||
setup_global_skill_info() {
|
||||
// 设置全局变量,让执行器能够获取到智能体信息
|
||||
if (this.frm && this.frm.pg && this.frm.pg.name) {
|
||||
window.current_skill_name = this.frm.pg.name;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user