重命名:agent_name - skill_name
This commit is contained in:
parent
8f11cf6dc9
commit
cca2946ad4
@ -86,7 +86,7 @@ const stats = reactive({
|
||||
const loadStats = async () => {
|
||||
try {
|
||||
// 第一行:原来的4个统计
|
||||
// 获取智能体总数
|
||||
// 获取技能总数
|
||||
const agentsResult = await getCount('Local Ai Skill')
|
||||
if (agentsResult.success) {
|
||||
stats.agents = agentsResult.count || 0
|
||||
|
||||
@ -124,7 +124,7 @@ import { api } from '@/shared/api/common'
|
||||
|
||||
const props = defineProps<{
|
||||
show: boolean
|
||||
agentName: string
|
||||
skillName: string
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
@ -158,7 +158,7 @@ function execStatusType(exec: any) {
|
||||
}
|
||||
|
||||
watch(() => props.show, (val) => {
|
||||
if (val && props.agentName) {
|
||||
if (val && props.skillName) {
|
||||
refresh()
|
||||
}
|
||||
})
|
||||
@ -169,11 +169,11 @@ function afterLeave() {
|
||||
}
|
||||
|
||||
async function refresh() {
|
||||
if (!props.agentName) return
|
||||
if (!props.skillName) return
|
||||
loading.value = true
|
||||
try {
|
||||
const res = await api.call('jingrow.ai.pagetype.ai_skill.ai_skill.get_skill_execution_logs', {
|
||||
agent_name: props.agentName
|
||||
skill_name: props.skillName
|
||||
})
|
||||
const result = res?.message || res
|
||||
const list = result?.success ? (result.data || []) : []
|
||||
|
||||
@ -63,15 +63,15 @@ const executing = ref(false)
|
||||
async function handleExecute() {
|
||||
try {
|
||||
executing.value = true
|
||||
const agentName = props.context.row.name
|
||||
const skillName = props.context.row.name
|
||||
|
||||
if (!agentName) {
|
||||
message.error(props.context.t('Agent name is required'))
|
||||
if (!skillName) {
|
||||
message.error(props.context.t('Skill name is required'))
|
||||
return
|
||||
}
|
||||
|
||||
const res = await api.call('jingrow.ai.pagetype.ai_skill.ai_skill.execute_skill_by_name', {
|
||||
agent_name: agentName
|
||||
skill_name: skillName
|
||||
})
|
||||
|
||||
const result = res?.message || res
|
||||
@ -93,27 +93,27 @@ async function handleFlowBuilder() {
|
||||
const name = props.context.row.name
|
||||
let flowData: any = {}
|
||||
|
||||
// 如果列表数据中没有 agent_flow 字段,需要从 API 获取完整记录
|
||||
if (props.context.row.agent_flow !== undefined && props.context.row.agent_flow !== null) {
|
||||
const raw = props.context.row.agent_flow
|
||||
// 如果列表数据中没有 skill_flow 字段,需要从 API 获取完整记录
|
||||
if (props.context.row.skill_flow !== undefined && props.context.row.skill_flow !== null) {
|
||||
const raw = props.context.row.skill_flow
|
||||
flowData = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
}
|
||||
} else {
|
||||
// 从 API 获取完整记录数据,包含 agent_flow 字段
|
||||
// 从 API 获取完整记录数据,包含 skill_flow 字段
|
||||
try {
|
||||
const response = await axios.get(`/api/data/${encodeURIComponent(props.context.entity)}/${encodeURIComponent(name)}`)
|
||||
|
||||
const record = response.data?.data || {}
|
||||
const raw = record.agent_flow ?? {}
|
||||
const raw = record.skill_flow ?? {}
|
||||
flowData = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取智能体数据失败:', error)
|
||||
message.error(props.context.t('Failed to load agent data'))
|
||||
console.error('获取技能数据失败:', error)
|
||||
message.error(props.context.t('Failed to load skill data'))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="ai-agent-toolbar-wrapper">
|
||||
<div class="ai-skill-toolbar-wrapper">
|
||||
<n-space align="center">
|
||||
<!-- 侧边栏位置切换按钮 -->
|
||||
<n-button
|
||||
@ -182,7 +182,7 @@
|
||||
<!-- 执行日志对话框 -->
|
||||
<ExecutionLogDialog
|
||||
v-model:show="showLogDialog"
|
||||
:agent-name="props.record?.name || props.id"
|
||||
:skill-name="props.record?.name || props.id"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -264,9 +264,9 @@ onMounted(() => {
|
||||
async function handleExecute() {
|
||||
if (isNew.value) return
|
||||
|
||||
const agentName = props.record?.name
|
||||
if (!agentName) {
|
||||
message.error(t('Agent name is required'))
|
||||
const skillName = props.record?.name
|
||||
if (!skillName) {
|
||||
message.error(t('Skill name is required'))
|
||||
return
|
||||
}
|
||||
|
||||
@ -274,7 +274,7 @@ async function handleExecute() {
|
||||
executing.value = true
|
||||
|
||||
const res = await api.call('jingrow.ai.pagetype.ai_skill.ai_skill.execute_skill_by_name', {
|
||||
agent_name: agentName
|
||||
skill_name: skillName
|
||||
})
|
||||
|
||||
const result = res?.message || res
|
||||
@ -294,7 +294,7 @@ async function handleExecute() {
|
||||
// 流程编排按钮处理函数
|
||||
async function handleFlowBuilder() {
|
||||
try {
|
||||
const raw = props.record?.agent_flow ?? {}
|
||||
const raw = props.record?.skill_flow ?? {}
|
||||
let flowData: any = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
@ -313,22 +313,22 @@ async function handleFlowBuilder() {
|
||||
|
||||
// 发布到市场按钮处理函数
|
||||
function handlePublish() {
|
||||
if (isNew.value || !props.record?.agent_name) {
|
||||
message.warning(t('Please save the agent first'))
|
||||
if (isNew.value || !props.record?.skill_name) {
|
||||
message.warning(t('Please save the skill first'))
|
||||
return
|
||||
}
|
||||
|
||||
const agentName = props.record.agent_name
|
||||
const agentFlow = props.record.agent_flow
|
||||
const skillName = props.record.skill_name
|
||||
const skillFlow = props.record.skill_flow
|
||||
|
||||
if (!agentFlow) {
|
||||
message.warning(t('Agent flow data is required for publishing'))
|
||||
if (!skillFlow) {
|
||||
message.warning(t('Skill flow data is required for publishing'))
|
||||
return
|
||||
}
|
||||
|
||||
dialog.info({
|
||||
title: t('Publish to Agent Marketplace'),
|
||||
content: t('Are you sure you want to publish agent "{0}" to the marketplace?').replace('{0}', agentName),
|
||||
title: t('Publish to Skill Marketplace'),
|
||||
content: t('Are you sure you want to publish skill "{0}" to the marketplace?').replace('{0}', skillName),
|
||||
positiveText: t('Confirm'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: () => {
|
||||
@ -341,33 +341,33 @@ async function performPublish() {
|
||||
try {
|
||||
publishing.value = true
|
||||
|
||||
const agentName = props.record?.agent_name || ''
|
||||
const agentFlow = props.record?.agent_flow
|
||||
const skillName = props.record?.skill_name || ''
|
||||
const skillFlow = props.record?.skill_flow
|
||||
|
||||
if (!agentFlow) {
|
||||
throw new Error(t('Agent flow data is required'))
|
||||
if (!skillFlow) {
|
||||
throw new Error(t('Skill flow data is required'))
|
||||
}
|
||||
|
||||
// agent_flow 是 JSON 字段类型,从数据库获取时可能是字符串或对象
|
||||
// skill_flow 是 JSON 字段类型,从数据库获取时可能是字符串或对象
|
||||
// 统一处理:如果是字符串则解析为对象,如果是对象则直接使用
|
||||
let flowData = agentFlow
|
||||
if (typeof agentFlow === 'string') {
|
||||
let flowData = skillFlow
|
||||
if (typeof skillFlow === 'string') {
|
||||
try {
|
||||
flowData = JSON.parse(agentFlow)
|
||||
flowData = JSON.parse(skillFlow)
|
||||
} catch (e) {
|
||||
throw new Error(t('Invalid agent flow data format'))
|
||||
throw new Error(t('Invalid skill flow data format'))
|
||||
}
|
||||
} else if (typeof agentFlow !== 'object' || agentFlow === null) {
|
||||
throw new Error(t('Agent flow data must be a valid JSON object'))
|
||||
} else if (typeof skillFlow !== 'object' || skillFlow === null) {
|
||||
throw new Error(t('Skill flow data must be a valid JSON object'))
|
||||
}
|
||||
|
||||
// 准备发布数据(flowData 现在是对象,后端会处理 JSON 序列化)
|
||||
const publishData = {
|
||||
agent_name: agentName,
|
||||
title: props.record?.title || agentName,
|
||||
skill_name: skillName,
|
||||
title: props.record?.title || skillName,
|
||||
subtitle: props.record?.subtitle || '',
|
||||
description: props.record?.description || '',
|
||||
agent_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
skill_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/agent/publish', publishData, {
|
||||
@ -377,12 +377,12 @@ async function performPublish() {
|
||||
})
|
||||
|
||||
if (response.data.success) {
|
||||
message.success(response.data.message || t('Agent published successfully'))
|
||||
message.success(response.data.message || t('Skill published successfully'))
|
||||
} else {
|
||||
throw new Error(response.data.message || t('Publish failed'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('发布智能体失败:', error)
|
||||
console.error('发布技能失败:', error)
|
||||
const errorMsg = error?.response?.data?.detail || error?.response?.data?.message || error?.message || t('Publish failed, please check permission and server logs')
|
||||
message.error(errorMsg)
|
||||
} finally {
|
||||
@ -509,7 +509,7 @@ async function handleRenameConfirm() {
|
||||
|
||||
<style scoped>
|
||||
/* 工具栏外层包裹容器,消除 fragment 警告,对父级 Space 透明 */
|
||||
.ai-agent-toolbar-wrapper {
|
||||
.ai-skill-toolbar-wrapper {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
|
||||
@ -63,15 +63,15 @@ const executing = ref(false)
|
||||
async function handleExecute() {
|
||||
try {
|
||||
executing.value = true
|
||||
const agentName = props.context.row.name
|
||||
const skillName = props.context.row.name
|
||||
|
||||
if (!agentName) {
|
||||
message.error(props.context.t('Agent name is required'))
|
||||
if (!skillName) {
|
||||
message.error(props.context.t('Skill name is required'))
|
||||
return
|
||||
}
|
||||
|
||||
const res = await api.call('jingrow.ai.utils.jlocal.execute_local_ai_skill', {
|
||||
name: agentName
|
||||
name: skillName
|
||||
})
|
||||
|
||||
const result = res?.message || res
|
||||
@ -93,27 +93,27 @@ async function handleFlowBuilder() {
|
||||
const name = props.context.row.name
|
||||
let flowData: any = {}
|
||||
|
||||
// 如果列表数据中没有 agent_flow 字段,需要从 API 获取完整记录
|
||||
if (props.context.row.agent_flow !== undefined && props.context.row.agent_flow !== null) {
|
||||
const raw = props.context.row.agent_flow
|
||||
// 如果列表数据中没有 skill_flow 字段,需要从 API 获取完整记录
|
||||
if (props.context.row.skill_flow !== undefined && props.context.row.skill_flow !== null) {
|
||||
const raw = props.context.row.skill_flow
|
||||
flowData = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
}
|
||||
} else {
|
||||
// 从 API 获取完整记录数据,包含 agent_flow 字段
|
||||
// 从 API 获取完整记录数据,包含 skill_flow 字段
|
||||
try {
|
||||
const response = await axios.get(`/api/data/${encodeURIComponent(props.context.entity)}/${encodeURIComponent(name)}`)
|
||||
|
||||
const record = response.data?.data || {}
|
||||
const raw = record.agent_flow ?? {}
|
||||
const raw = record.skill_flow ?? {}
|
||||
flowData = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取智能体数据失败:', error)
|
||||
message.error(props.context.t('Failed to load agent data'))
|
||||
console.error('获取技能数据失败:', error)
|
||||
message.error(props.context.t('Failed to load skill data'))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@ -188,9 +188,9 @@ onMounted(() => {
|
||||
async function handleExecute() {
|
||||
if (isNew.value) return
|
||||
|
||||
const agentName = props.record?.name
|
||||
if (!agentName) {
|
||||
message.error(t('Agent name is required'))
|
||||
const skillName = props.record?.name
|
||||
if (!skillName) {
|
||||
message.error(t('Skill name is required'))
|
||||
return
|
||||
}
|
||||
|
||||
@ -198,7 +198,7 @@ async function handleExecute() {
|
||||
executing.value = true
|
||||
|
||||
const res = await api.call('jingrow.ai.utils.jlocal.execute_local_ai_skill', {
|
||||
name: agentName
|
||||
name: skillName
|
||||
})
|
||||
|
||||
const result = res?.message || res
|
||||
@ -218,7 +218,7 @@ async function handleExecute() {
|
||||
// 流程编排按钮处理函数
|
||||
async function handleFlowBuilder() {
|
||||
try {
|
||||
const raw = props.record?.agent_flow ?? {}
|
||||
const raw = props.record?.skill_flow ?? {}
|
||||
let flowData: any = raw
|
||||
if (typeof raw === 'string') {
|
||||
try { flowData = JSON.parse(raw) } catch { flowData = {} }
|
||||
@ -237,22 +237,22 @@ async function handleFlowBuilder() {
|
||||
|
||||
// 发布到市场按钮处理函数
|
||||
function handlePublish() {
|
||||
if (isNew.value || !props.record?.agent_name) {
|
||||
message.warning(t('Please save the agent first'))
|
||||
if (isNew.value || !props.record?.skill_name) {
|
||||
message.warning(t('Please save the skill first'))
|
||||
return
|
||||
}
|
||||
|
||||
const agentName = props.record.agent_name
|
||||
const agentFlow = props.record.agent_flow
|
||||
const skillName = props.record.skill_name
|
||||
const skillFlow = props.record.skill_flow
|
||||
|
||||
if (!agentFlow) {
|
||||
message.warning(t('Agent flow data is required for publishing'))
|
||||
if (!skillFlow) {
|
||||
message.warning(t('Skill flow data is required for publishing'))
|
||||
return
|
||||
}
|
||||
|
||||
dialog.info({
|
||||
title: t('Publish to Agent Marketplace'),
|
||||
content: t('Are you sure you want to publish agent "{0}" to the marketplace?').replace('{0}', agentName),
|
||||
title: t('Publish to Skill Marketplace'),
|
||||
content: t('Are you sure you want to publish skill "{0}" to the marketplace?').replace('{0}', skillName),
|
||||
positiveText: t('Confirm'),
|
||||
negativeText: t('Cancel'),
|
||||
onPositiveClick: () => {
|
||||
@ -265,33 +265,33 @@ async function performPublish() {
|
||||
try {
|
||||
publishing.value = true
|
||||
|
||||
const agentName = props.record?.agent_name || ''
|
||||
const agentFlow = props.record?.agent_flow
|
||||
const skillName = props.record?.skill_name || ''
|
||||
const skillFlow = props.record?.skill_flow
|
||||
|
||||
if (!agentFlow) {
|
||||
throw new Error(t('Agent flow data is required'))
|
||||
if (!skillFlow) {
|
||||
throw new Error(t('Skill flow data is required'))
|
||||
}
|
||||
|
||||
// agent_flow 是 JSON 字段类型,从数据库获取时可能是字符串或对象
|
||||
// skill_flow 是 JSON 字段类型,从数据库获取时可能是字符串或对象
|
||||
// 统一处理:如果是字符串则解析为对象,如果是对象则直接使用
|
||||
let flowData = agentFlow
|
||||
if (typeof agentFlow === 'string') {
|
||||
let flowData = skillFlow
|
||||
if (typeof skillFlow === 'string') {
|
||||
try {
|
||||
flowData = JSON.parse(agentFlow)
|
||||
flowData = JSON.parse(skillFlow)
|
||||
} catch (e) {
|
||||
throw new Error(t('Invalid agent flow data format'))
|
||||
throw new Error(t('Invalid skill flow data format'))
|
||||
}
|
||||
} else if (typeof agentFlow !== 'object' || agentFlow === null) {
|
||||
throw new Error(t('Agent flow data must be a valid JSON object'))
|
||||
} else if (typeof skillFlow !== 'object' || skillFlow === null) {
|
||||
throw new Error(t('Skill flow data must be a valid JSON object'))
|
||||
}
|
||||
|
||||
// 准备发布数据(flowData 现在是对象,后端会处理 JSON 序列化)
|
||||
const publishData = {
|
||||
agent_name: agentName,
|
||||
title: props.record?.title || agentName,
|
||||
skill_name: skillName,
|
||||
title: props.record?.title || skillName,
|
||||
subtitle: props.record?.subtitle || '',
|
||||
description: props.record?.description || '',
|
||||
agent_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
skill_flow: flowData // 对象格式,axios 会自动序列化为 JSON
|
||||
}
|
||||
|
||||
const response = await axios.post('/jingrow/agent/publish', publishData, {
|
||||
@ -301,12 +301,12 @@ async function performPublish() {
|
||||
})
|
||||
|
||||
if (response.data.success) {
|
||||
message.success(response.data.message || t('Agent published successfully'))
|
||||
message.success(response.data.message || t('Skill published successfully'))
|
||||
} else {
|
||||
throw new Error(response.data.message || t('Publish failed'))
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('发布智能体失败:', error)
|
||||
console.error('发布技能失败:', error)
|
||||
const errorMsg = error?.response?.data?.detail || error?.response?.data?.message || error?.message || t('Publish failed, please check permission and server logs')
|
||||
message.error(errorMsg)
|
||||
} finally {
|
||||
|
||||
@ -9,7 +9,7 @@ def get_all_ai_skills():
|
||||
"""获取所有启用的事件驱动Ai Skill,支持按PageType和Module分组"""
|
||||
skills_list = jingrow.get_all(
|
||||
"Ai Skill",
|
||||
fields=["name", "agent_name", "trigger_mode", "event_type", "target_pagetype", "target_module", "condition"],
|
||||
fields=["name", "skill_name", "trigger_mode", "event_type", "target_pagetype", "target_module", "condition"],
|
||||
filters={"enabled": True, "trigger_mode": "Event Trigger"},
|
||||
)
|
||||
|
||||
@ -84,7 +84,7 @@ def _add_skill_to_queue(skill, pg):
|
||||
jingrow.local._ai_skill_queue = []
|
||||
jingrow.db.after_commit.add(flush_ai_skill_execution_queue)
|
||||
|
||||
jingrow.local._ai_skill_queue.append(jingrow._dict(pg=pg, agent=skill))
|
||||
jingrow.local._ai_skill_queue.append(jingrow._dict(pg=pg, skill=skill))
|
||||
|
||||
|
||||
def flush_ai_skill_execution_queue():
|
||||
@ -101,7 +101,7 @@ def flush_ai_skill_execution_queue():
|
||||
# 去重:基于 (skill.name, pg.name)
|
||||
# 'pg' 保存最后一个实例的值
|
||||
for execution in jingrow.local._ai_skill_queue:
|
||||
key = (execution.agent.get("name"), execution.pg.get("name"))
|
||||
key = (execution.skill.get("name"), execution.pg.get("name"))
|
||||
if key not in uniq_skills:
|
||||
uniq_skills.add(key)
|
||||
unique_last_instances.append(execution)
|
||||
@ -117,7 +117,7 @@ def flush_ai_skill_execution_queue():
|
||||
jingrow.enqueue(
|
||||
"jingrow.ai.pagetype.ai_skill.ai_skill.enqueue_ai_skill",
|
||||
pg=instance.pg,
|
||||
agent_name=instance.agent.get("name"),
|
||||
skill_name=instance.skill.get("name"),
|
||||
now=jingrow.flags.in_test,
|
||||
queue="default",
|
||||
)
|
||||
|
||||
@ -9,7 +9,7 @@ jingrow.ui.form.on("Ai Skill", {
|
||||
updateCustomProgressBar(frm);
|
||||
}
|
||||
// 增加可视化节点编辑按钮(直接显示为主按钮,不放在下拉菜单)
|
||||
frm.add_custom_button(__('智能体编排'), function() {
|
||||
frm.add_custom_button(__('技能编排'), function() {
|
||||
open_skill_flow_editor(frm);
|
||||
});
|
||||
}
|
||||
@ -58,8 +58,8 @@ function open_skill_flow_editor(frm) {
|
||||
const container = dialog.$body.find('#ai-skill-flow-builder-container')[0];
|
||||
if (!container) return;
|
||||
|
||||
// 直接使用当前表单的 agent_flow 数据
|
||||
let currentFlowData = frm.pg.agent_flow || {};
|
||||
// 直接使用当前表单的 skill_flow 数据
|
||||
let currentFlowData = frm.pg.skill_flow || {};
|
||||
|
||||
// 如果是字符串,尝试解析为对象
|
||||
if (typeof currentFlowData === 'string') {
|
||||
@ -119,7 +119,7 @@ function save_skill_flow(frm, dialog) {
|
||||
|
||||
// 格式化为多行美观JSON字符串
|
||||
const prettyJson = JSON.stringify(flowData, null, 2);
|
||||
frm.set_value('agent_flow', prettyJson);
|
||||
frm.set_value('skill_flow', prettyJson);
|
||||
|
||||
// 保存表单
|
||||
frm.save().then(() => {
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"progress",
|
||||
"section_break_xcls",
|
||||
"column_break_glmw",
|
||||
"agent_name",
|
||||
"skill_name"
|
||||
"ai_repeat",
|
||||
"enabled",
|
||||
"column_break_bzai",
|
||||
@ -20,8 +20,8 @@
|
||||
"target_module",
|
||||
"condition",
|
||||
"trigger_time",
|
||||
"agent_flow_tab",
|
||||
"agent_flow",
|
||||
"skill_flow_tab"
|
||||
"skill_flow"
|
||||
"排除关键词_tab",
|
||||
"exclude_prompts"
|
||||
],
|
||||
@ -101,21 +101,21 @@
|
||||
"label": "Condition"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_flow",
|
||||
"fieldname": "skill_flow",
|
||||
"fieldtype": "JSON",
|
||||
"label": "Agent Flow"
|
||||
"label": "Skill Flow"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_flow_tab",
|
||||
"fieldname": "skill_flow_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Agent Flow"
|
||||
"label": "Skill Flow"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_name",
|
||||
"fieldname": "skill_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"label": "智能体名称",
|
||||
"label": "技能名称",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@ -25,8 +25,8 @@ class AiSkill(Page):
|
||||
if TYPE_CHECKING:
|
||||
from jingrow.types import DF
|
||||
|
||||
agent_flow: DF.JSON | None
|
||||
agent_name: DF.Data
|
||||
skill_flow: DF.JSON | None
|
||||
skill_name: DF.Data
|
||||
ai_repeat: DF.Int
|
||||
condition: DF.SmallText | None
|
||||
enabled: DF.Check
|
||||
@ -48,8 +48,8 @@ class AiSkill(Page):
|
||||
if not self.progress:
|
||||
self.progress = 0
|
||||
|
||||
if self.agent_flow == "" or self.agent_flow is None:
|
||||
self.agent_flow = None
|
||||
if self.skill_flow == "" or self.skill_flow is None:
|
||||
self.skill_flow = None
|
||||
|
||||
def on_update(self):
|
||||
"""Post-update processing"""
|
||||
@ -64,8 +64,8 @@ class AiSkill(Page):
|
||||
# Only enqueue, don't execute synchronously
|
||||
jingrow.enqueue(
|
||||
"jingrow.ai.pagetype.ai_skill.ai_skill.execute_skill_task",
|
||||
agent_name=self.name,
|
||||
agent_pagetype=self.pagetype
|
||||
skill_name=self.name,
|
||||
skill_pagetype=self.pagetype
|
||||
)
|
||||
|
||||
def after_insert(self):
|
||||
@ -80,8 +80,8 @@ class AiSkill(Page):
|
||||
jingrow.db.commit()
|
||||
jingrow.enqueue(
|
||||
"jingrow.ai.pagetype.ai_skill.ai_skill.execute_skill_task",
|
||||
agent_name=self.name,
|
||||
agent_pagetype=self.pagetype
|
||||
skill_name=self.name,
|
||||
skill_pagetype=self.pagetype
|
||||
)
|
||||
|
||||
def on_trash(self):
|
||||
@ -94,9 +94,9 @@ class AiSkill(Page):
|
||||
|
||||
def _manage_scheduled_job(self):
|
||||
"""Manage scheduled job for the Ai Skill, create/update/delete based on current status"""
|
||||
agent_name = self.name
|
||||
skill_name = self.name
|
||||
cron = getattr(self, "trigger_time", None) or getattr(self, "cron_format", None)
|
||||
method_name = f"jingrow.ai.pagetype.ai_skill.ai_skill.execute_scheduled_skills:{agent_name}"
|
||||
method_name = f"jingrow.ai.pagetype.ai_skill.ai_skill.execute_scheduled_skills:{skill_name}"
|
||||
|
||||
# Check if a scheduled job already exists
|
||||
job = jingrow.db.exists("Scheduled Job Type", {"method": method_name})
|
||||
@ -140,18 +140,18 @@ class AiSkill(Page):
|
||||
self.progress = 20
|
||||
self.save(ignore_permissions=True)
|
||||
jingrow.db.commit()
|
||||
flow_data = self.agent_flow
|
||||
flow_data = self.skill_flow
|
||||
if isinstance(flow_data, str):
|
||||
try:
|
||||
flow_data = json.loads(flow_data)
|
||||
except Exception as e:
|
||||
async_update_field(self.pagetype, self.name, "status", "未完成")
|
||||
async_update_field(self.pagetype, self.name, "progress", 0)
|
||||
return {"success": False, "error": f"agent_flow is not valid JSON: {e}"}
|
||||
return {"success": False, "error": f"skill_flow is not valid JSON: {e}"}
|
||||
if not flow_data:
|
||||
async_update_field(self.pagetype, self.name, "status", "未完成")
|
||||
async_update_field(self.pagetype, self.name, "progress", 0)
|
||||
return {"success": False, "error": "agent_flow is empty"}
|
||||
return {"success": False, "error": "skill_flow is empty"}
|
||||
if initial_inputs is None or not initial_inputs:
|
||||
initial_inputs = {}
|
||||
repeat_count = getattr(self, "ai_repeat", 1) or 1
|
||||
@ -202,7 +202,7 @@ class AiSkill(Page):
|
||||
# Persist to Ai Skill Execution Log
|
||||
try:
|
||||
log = jingrow.new_pg("Ai Skill Execution Log")
|
||||
log.agent_name = self.name
|
||||
log.skill_name = self.name
|
||||
log.status = status_text
|
||||
log.total_iterations = repeat_count
|
||||
log.successful_iterations = success_count
|
||||
@ -233,11 +233,11 @@ class AiSkill(Page):
|
||||
final_result = {"success": False, "error": "All iterations failed", "total_executions": repeat_count, "successful_executions": 0}
|
||||
return final_result
|
||||
except Exception as e:
|
||||
jingrow.log_error("Ai Skill execution exception", f"agent_name={self.name}, error={str(e)}")
|
||||
jingrow.log_error("Ai Skill execution exception", f"skill_name={self.name}, error={str(e)}")
|
||||
# Also create Ai Skill Execution Log on exception
|
||||
try:
|
||||
log = jingrow.new_pg("Ai Skill Execution Log")
|
||||
log.agent_name = self.name
|
||||
log.skill_name = self.name
|
||||
log.status = "异常"
|
||||
log.end_time = str(jingrow.utils.now())
|
||||
log.node_results = json.dumps({"error": str(e)}, ensure_ascii=False, default=str)
|
||||
@ -411,76 +411,76 @@ def get_context(pg):
|
||||
}
|
||||
|
||||
|
||||
def execute_skill_task(agent_name, agent_pagetype):
|
||||
def execute_skill_task(skill_name, skill_pagetype):
|
||||
"""Execute Ai Skill task in background"""
|
||||
try:
|
||||
agent = jingrow.get_pg(agent_pagetype, agent_name)
|
||||
if not agent:
|
||||
skill = jingrow.get_pg(skill_pagetype, skill_name)
|
||||
if not skill:
|
||||
return
|
||||
agent.execute_skill()
|
||||
skill.execute_skill()
|
||||
except Exception as e:
|
||||
jingrow.log_error("Ai Skill task execution exception", f"agent_name={agent_name}, agent_pagetype={agent_pagetype}, error={str(e)}")
|
||||
jingrow.log_error("Ai Skill task execution exception", f"skill_name={skill_name}, skill_pagetype={skill_pagetype}, error={str(e)}")
|
||||
|
||||
|
||||
@jingrow.whitelist()
|
||||
def execute_skill_by_name(agent_name):
|
||||
def execute_skill_by_name(skill_name):
|
||||
"""Execute the specified Ai Skill (via RPC)"""
|
||||
if not agent_name:
|
||||
return {"success": False, "error": "agent_name is required"}
|
||||
if not skill_name:
|
||||
return {"success": False, "error": "skill_name is required"}
|
||||
|
||||
try:
|
||||
# check if the agent exists
|
||||
if not jingrow.db.exists('Ai Skill', agent_name):
|
||||
return {"success": False, "error": f"Ai Skill {agent_name} does not exist"}
|
||||
# check if the skill exists
|
||||
if not jingrow.db.exists('Ai Skill', skill_name):
|
||||
return {"success": False, "error": f"Ai Skill {skill_name} does not exist"}
|
||||
|
||||
# Execute asynchronously, don't block the frontend response
|
||||
jingrow.enqueue(
|
||||
method=execute_skill_task,
|
||||
agent_name=agent_name,
|
||||
agent_pagetype='Ai Skill',
|
||||
skill_name=skill_name,
|
||||
skill_pagetype='Ai Skill',
|
||||
queue='default',
|
||||
timeout=3600
|
||||
)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"message": "The agent execution task has been queued. Please check the execution status later."
|
||||
"message": "技能执行任务已加入队列,请稍后查看执行状态。"
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
jingrow.log_error("Ai Skill execution failed", f"agent_name={agent_name}, error={str(e)}")
|
||||
jingrow.log_error("Ai Skill execution failed", f"skill_name={skill_name}, error={str(e)}")
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
def enqueue_ai_skill(pg, agent_name):
|
||||
def enqueue_ai_skill(pg, skill_name):
|
||||
"""Execute Ai Skill task in background"""
|
||||
try:
|
||||
# Get the full Page instance via agent_name
|
||||
agent = jingrow.get_pg("Ai Skill", agent_name)
|
||||
if not agent:
|
||||
# Get the full Page instance via skill_name
|
||||
skill = jingrow.get_pg("Ai Skill", skill_name)
|
||||
if not skill:
|
||||
return
|
||||
|
||||
agent_name = getattr(agent, "agent_name", None)
|
||||
skill_name = getattr(skill, "skill_name", None)
|
||||
initial_inputs = {
|
||||
"pagetype": pg.get("pagetype"),
|
||||
"name": pg.get("name"),
|
||||
"agent_name": agent_name
|
||||
"skill_name": skill_name
|
||||
}
|
||||
|
||||
agent.execute_skill(initial_inputs=initial_inputs)
|
||||
skill.execute_skill(initial_inputs=initial_inputs)
|
||||
|
||||
except Exception as e:
|
||||
jingrow.log_error("Ai Skill execution failed", f"Ai Skill {agent_name} execution failed: {str(e)}")
|
||||
jingrow.log_error("Ai Skill execution failed", f"Ai Skill {skill_name} execution failed: {str(e)}")
|
||||
|
||||
|
||||
@jingrow.whitelist()
|
||||
def get_skill_execution_logs(agent_name):
|
||||
def get_skill_execution_logs(skill_name):
|
||||
"""Get all execution logs for the specified Ai Skill (ordered by start_time desc)"""
|
||||
try:
|
||||
logs = jingrow.get_all(
|
||||
"Ai Skill Execution Log",
|
||||
filters={"agent_name": agent_name},
|
||||
fields=["name", "agent_name", "status", "start_time", "end_time", "total_iterations", "successful_iterations", "node_results"],
|
||||
filters={"skill_name": skill_name},
|
||||
fields=["name", "skill_name", "status", "start_time", "end_time", "total_iterations", "successful_iterations", "node_results"],
|
||||
order_by="start_time desc"
|
||||
)
|
||||
# node_results is a JSON string, parse it
|
||||
@ -495,19 +495,19 @@ def get_skill_execution_logs(agent_name):
|
||||
return {"success": False, "error": str(e)}
|
||||
|
||||
|
||||
def execute_scheduled_skills(agent_name):
|
||||
def execute_scheduled_skills(skill_name):
|
||||
"""Scheduled task entry point, execute the specified Ai Skill"""
|
||||
try:
|
||||
if not agent_name:
|
||||
if not skill_name:
|
||||
return
|
||||
|
||||
agent = jingrow.get_pg("Ai Skill", agent_name)
|
||||
if not agent:
|
||||
skill = jingrow.get_pg("Ai Skill", skill_name)
|
||||
if not skill:
|
||||
return
|
||||
|
||||
if not agent.enabled or agent.trigger_mode != "Scheduled Trigger":
|
||||
if not skill.enabled or skill.trigger_mode != "Scheduled Trigger":
|
||||
return
|
||||
|
||||
agent.execute_skill()
|
||||
skill.execute_skill()
|
||||
except Exception as e:
|
||||
jingrow.log_error("Scheduled Ai Skill execution exception", f"agent_name={agent_name}, error={str(e)}")
|
||||
jingrow.log_error("Scheduled Ai Skill execution exception", f"skill_name={skill_name}, error={str(e)}")
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"creation": "2026-06-24 10:00:00.000000",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"agent_name",
|
||||
"skill_name"
|
||||
"status",
|
||||
"column_break_basic",
|
||||
"start_time",
|
||||
@ -17,11 +17,11 @@
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "agent_name",
|
||||
"fieldname": "skill_name",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Agent Name",
|
||||
"label": "Skill Name",
|
||||
"options": "Ai Skill",
|
||||
"reqd": 1,
|
||||
"search_index": 1
|
||||
|
||||
@ -14,7 +14,7 @@ class AiSkillExecutionLog(Page):
|
||||
if TYPE_CHECKING:
|
||||
from jingrow.types import DF
|
||||
|
||||
agent_name: DF.Link
|
||||
skill_name: DF.Link
|
||||
end_time: DF.Datetime | None
|
||||
execution_flow: DF.JSON | None
|
||||
node_results: DF.JSON | None
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
"progress",
|
||||
"section_break_xcls",
|
||||
"column_break_glmw",
|
||||
"agent_name",
|
||||
"skill_name"
|
||||
"ai_repeat",
|
||||
"enabled",
|
||||
"column_break_bzai",
|
||||
@ -20,8 +20,8 @@
|
||||
"target_module",
|
||||
"condition",
|
||||
"trigger_time",
|
||||
"agent_flow_tab",
|
||||
"agent_flow",
|
||||
"skill_flow_tab"
|
||||
"skill_flow"
|
||||
"排除关键词_tab",
|
||||
"exclude_prompts"
|
||||
],
|
||||
@ -103,22 +103,22 @@
|
||||
"label": "Condition"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_flow",
|
||||
"fieldname": "skill_flow",
|
||||
"fieldtype": "JSON",
|
||||
"label": "Agent Flow"
|
||||
"label": "Skill Flow"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_flow_tab",
|
||||
"fieldname": "skill_flow_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Agent Flow"
|
||||
"label": "Skill Flow"
|
||||
},
|
||||
{
|
||||
"fieldname": "agent_name",
|
||||
"fieldname": "skill_name",
|
||||
"fieldtype": "Data",
|
||||
"in_global_search": 1,
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "智能体名称",
|
||||
"label": "技能名称",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
|
||||
@ -14,8 +14,8 @@ class LocalAiSkill(Page):
|
||||
if TYPE_CHECKING:
|
||||
from jingrow.types import DF
|
||||
|
||||
agent_flow: DF.JSON | None
|
||||
agent_name: DF.Data
|
||||
skill_flow: DF.JSON | None
|
||||
skill_name: DF.Data
|
||||
ai_repeat: DF.Int
|
||||
condition: DF.SmallText | None
|
||||
enabled: DF.Check
|
||||
@ -29,8 +29,8 @@ class LocalAiSkill(Page):
|
||||
# end: auto-generated types
|
||||
|
||||
def validate(self):
|
||||
if getattr(self, "agent_flow", None) in (None, ""):
|
||||
self.agent_flow = None
|
||||
if getattr(self, "skill_flow", None) in (None, ""):
|
||||
self.skill_flow = None
|
||||
|
||||
def on_update(self):
|
||||
"""更新时管理定时任务"""
|
||||
@ -45,12 +45,12 @@ class LocalAiSkill(Page):
|
||||
self._manage_scheduled_job()
|
||||
|
||||
def _manage_scheduled_job(self):
|
||||
"""管理定时Ai Skill的定时任务,根据当前状态创建、更新或删除定时任务
|
||||
"""管理定时技能的定时任务,根据当前状态创建、更新或删除定时任务
|
||||
参考 Jingrow 系统的 Ai Skill._manage_scheduled_job 实现
|
||||
"""
|
||||
agent_id = self.name
|
||||
skill_id = self.name
|
||||
cron = getattr(self, "trigger_time", None) or getattr(self, "cron_format", None)
|
||||
method_name = f"jingrow/agents/execute_scheduled_skill:{agent_id}"
|
||||
method_name = f"jingrow/agents/execute_scheduled_skill:{skill_id}"
|
||||
|
||||
# 检查是否存在对应的定时任务
|
||||
job = jingrow.db.exists("Local Scheduled Job", {"method": method_name})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user