Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def execute(self):
"position": position.get("children") if position else None,
"chunk_id": workflow_params.get("chunk_id"),
"form_data": workflow_params.get("form_data"),
"default_model_setting": tool_workflow_version.default_model_setting or {},
**parameters,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Generated by Django 6.1 on 2026-09-10 07:58

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("tools", "0007_alter_tool_tool_type_toolworkflow_and_more"),
]

operations = [
migrations.AddField(
model_name="toolworkflow",
name="default_model_setting",
field=models.JSONField(default=dict, verbose_name="默认模型"),
),
migrations.AddField(
model_name="toolworkflowversion",
name="default_model_setting",
field=models.JSONField(default=dict, verbose_name="默认模型"),
),
migrations.AlterField(
model_name="tool",
name="tool_type",
field=models.CharField(
choices=[
("INTERNAL", "内置"),
("CUSTOM", "自定义"),
("SKILL", "技能"),
("MCP", "MCP工具"),
("DATA_SOURCE", "数据源"),
("WORKFLOW", "工作流"),
],
db_index=True,
default="CUSTOM",
max_length=20,
verbose_name="工具类型",
),
),
migrations.AlterField(
model_name="toolrecord",
name="source_type",
field=models.CharField(
choices=[
("APPLICATION", "Application"),
("KNOWLEDGE", "Knowledge"),
("TOOL", "Tool"),
("TRIGGER", "Trigger"),
],
default="APPLICATION",
max_length=256,
verbose_name="触发器任务类型",
),
),
]
20 changes: 13 additions & 7 deletions apps/tools/models/tool_workflow.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
# coding=utf-8
"""
@project: MaxKB
@Author:虎虎
@file: tool_workflow.py
@date:2026/3/3 13:59
@desc:
@project: MaxKB
@Author:虎虎
@file: tool_workflow.py
@date:2026/3/3 13:59
@desc:
"""

from django.db import models

from common.mixins.app_model_mixin import AppModelMixin
Expand All @@ -18,13 +19,16 @@ class ToolWorkflow(AppModelMixin):
"""
知识库工作流表
"""

id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
tool = models.OneToOneField(Tool, on_delete=models.CASCADE, verbose_name="工具",
db_constraint=False, related_name='workflow')
tool = models.OneToOneField(
Tool, on_delete=models.CASCADE, verbose_name="工具", db_constraint=False, related_name="workflow"
)
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
is_publish = models.BooleanField(verbose_name="是否发布", default=False, db_index=True)
publish_time = models.DateTimeField(verbose_name="发布时间", null=True, blank=True)
default_model_setting = models.JSONField(verbose_name="默认模型", default=dict)

class Meta:
db_table = "tool_workflow"
Expand All @@ -34,13 +38,15 @@ class ToolWorkflowVersion(AppModelMixin):
"""
知识库工作流版本表 - 记录工作流历史版本
"""

id = models.UUIDField(primary_key=True, max_length=128, default=uuid.uuid7, editable=False, verbose_name="主键id")
tool = models.ForeignKey(Tool, on_delete=models.CASCADE, verbose_name="工具", db_constraint=False)
workspace_id = models.CharField(max_length=64, verbose_name="工作空间id", default="default", db_index=True)
name = models.CharField(verbose_name="版本名称", max_length=128, default="")
work_flow = models.JSONField(verbose_name="工作流数据", default=dict)
publish_user_id = models.UUIDField(verbose_name="发布者id", max_length=128, default=None, null=True)
publish_user_name = models.CharField(verbose_name="发布者名称", max_length=128, default="")
default_model_setting = models.JSONField(verbose_name="默认模型", default=dict)

class Meta:
db_table = "tool_workflow_version"
5 changes: 5 additions & 0 deletions apps/tools/serializers/tool_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ def debug(self, instance: Dict, user, with_valid=True):
self.is_valid(raise_exception=True)
tool_workflow = QuerySet(ToolWorkflow).filter(tool_id=self.data.get("tool_id")).first()
workspace_id = tool_workflow.workspace_id
default_model_setting = tool_workflow.default_model_setting
tool_record_id = instance.get("chat_record_id") or str(uuid.uuid7())
# 表单节点等断点续跑:position 指向要从其恢复执行的节点,机制与 chat 一致
position = instance.get("position")
Expand All @@ -184,6 +185,7 @@ def debug(self, instance: Dict, user, with_valid=True):
"debug": True,
"workspace_id": workspace_id,
"user_id": self.data.get("user_id"),
"default_model_setting": default_model_setting,
**{k: v for k, v in instance.items() if k not in identity_keys},
}

Expand Down Expand Up @@ -356,6 +358,7 @@ def publish(self, with_valid=True):
publish_user_id=user_id,
publish_user_name=user.username,
workspace_id=workspace_id,
default_model_setting=tool_workflow.default_model_setting,
)
work_flow_version.save()
QuerySet(ToolWorkflow).filter(tool_id=self.data.get("tool_id")).update(
Expand Down Expand Up @@ -444,11 +447,13 @@ def edit(self, instance: Dict):
"tool_id": self.data.get("tool_id"),
"workspace_id": workflow_id,
"work_flow": instance.get("work_flow", {}),
"default_model_setting": instance.get("default_model_setting", {}),
},
defaults={
"tool_id": self.data.get("tool_id"),
"workspace_id": workflow_id,
"work_flow": instance.get("work_flow"),
"default_model_setting": instance.get("default_model_setting", {}),
},
)
# 当前用户可修改关联的知识库列表
Expand Down
2 changes: 2 additions & 0 deletions ui/src/api/types/tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import type LogicFlow from '@logicflow/core'
import { TOOL_SCOPE, TOOL_TYPE } from '@/api/enums'
import type { DynamicFormField } from './common'
import type { DefaultModelSettingPayload } from '@/api/types/model.ts'

export type ToolScope = (typeof TOOL_SCOPE)[keyof typeof TOOL_SCOPE]
export type ToolType = (typeof TOOL_TYPE)[keyof typeof TOOL_TYPE]
Expand Down Expand Up @@ -71,6 +72,7 @@ export interface ToolItem {
}

export interface ToolWorkflowDetail {
default_model_setting?: DefaultModelSettingPayload
create_time?: string
id: string
is_publish: boolean
Expand Down
49 changes: 45 additions & 4 deletions ui/src/views/workflow/tool/ToolWorkflowView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { cloneDeep } from 'lodash'
import ModelApi from '@/api/admin/workspace/model/model'
import ToolApi from '@/api/admin/workspace/tool/tool'
import ToolWorkflowApi from '@/api/admin/workspace/tool/workflow'
import type { ToolItem, ToolWorkflowDetail } from '@/api/types'
import { MsgConfirm, MsgSuccess } from '@/utils/message'
import type { DefaultModelSettingPayload, ToolItem, ToolWorkflowDetail } from '@/api/types'
import { MsgConfirm, MsgSuccess, MsgError } from '@/utils/message'
import WorkflowCanvas from '@/workflow-canvas/index.vue'
import { defaultToolNodes } from '@/workflow-canvas/config/node-mapping'
import { WorkflowMode } from '@/workflow-canvas/types'
import WorkflowViewLayout from '../components/WorkflowViewLayout.vue'
import DefaultModelSettingButton from '@/views/workflow/components/default-model-setting/DefaultModelSettingButton.vue'

defineOptions({ name: 'ToolWorkflowView' })

Expand All @@ -35,6 +36,7 @@ const workflowRef = useTemplateRef<InstanceType<typeof WorkflowCanvas>>('workflo
const toolDetail = ref<ToolItem>()
const loading = ref(false)
const saving = ref(false)
const publishing = ref(false)
const savedWorkflow = ref<LogicFlow.GraphData>()
const saveTime = ref<Date | string>()

Expand All @@ -57,8 +59,9 @@ function saveToolWorkflow(graphData = getGraphData(), showMessage = false) {
if (!graphData) return Promise.resolve<ToolWorkflowDetail | undefined>(undefined)

saving.value = true
return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow: graphData })
return ToolWorkflowApi.putToolWorkflow(toolId, { work_flow: graphData, default_model_setting: cloneDeep(defaultModelSetting.value) })
.then((toolWorkflow) => {
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
saveTime.value = toolWorkflow.update_time || new Date()
setSavedWorkflow(graphData)
if (showMessage) MsgSuccess('保存成功')
Expand All @@ -69,15 +72,43 @@ function saveToolWorkflow(graphData = getGraphData(), showMessage = false) {
})
}

/* 应用默认模型设置:抽屉提交后暂存,保存失败时从详情回滚。 */
const defaultModelSetting = ref<DefaultModelSettingPayload>({})

function handleApplyDefaultModelToAll(graphData: LogicFlow.GraphData) {
workflowRef.value?.renderGraphData(graphData)
}

function handleSaveDefaultModelSetting(settings: DefaultModelSettingPayload) {
defaultModelSetting.value = cloneDeep(settings)
return handleSave()
}

function handleSave() {
saveToolWorkflow(undefined, true)
}

function handlePublish() {
if (!workflowRef.value) return

publishing.value = true
workflowRef.value
.validate()
.then(() => saveToolWorkflow()) // 先保存未落库的画布改动
.then(() => ToolWorkflowApi.putToolWorkflowPublish(toolId))
.then(() => MsgSuccess('发布成功'))
.catch(() => MsgError('发布失败'))
.finally(() => {
publishing.value = false
})
}

function loadToolWorkflow() {
loading.value = true
return Promise.all([ToolApi.getToolDetail(toolId), ToolWorkflowApi.getToolWorkflow(toolId)])
.then(([tool, toolWorkflow]) => {
toolDetail.value = tool
defaultModelSetting.value = cloneDeep(toolWorkflow.default_model_setting ?? {})
saveTime.value = toolWorkflow.update_time

const workflow = toolWorkflow.work_flow?.nodes?.length ? toolWorkflow.work_flow : DEFAULT_WORKFLOW
Expand Down Expand Up @@ -133,9 +164,19 @@ onMounted(() => {
<template>
<WorkflowViewLayout :loading="loading" :title="toolDetail?.name" :save-time="saveTime" @back="handleBack">
<template #actions>
<DefaultModelSettingButton
:model-value="defaultModelSetting"
:model-api="ModelApi"
:get-graph-data="getGraphData"
:disabled="loading || saving || publishing"
@save="handleSaveDefaultModelSetting"
@apply-to-all="handleApplyDefaultModelToAll"
/>

<el-button type="primary" :loading="publishing" :disabled="loading || saving || publishing" @click="handlePublish"> 发布 </el-button>
<el-button plain :loading="saving" :disabled="loading || saving" @click="handleSave"> 保存 </el-button>
</template>

<WorkflowCanvas ref="workflowRef" class="min-h-0 flex-1" :loop-workflow-mode="WorkflowMode.ToolLoop" :workflow-mode="WorkflowMode.Tool" />
<WorkflowCanvas ref="workflowRef" class="min-h-0 flex-1" :default-model-settings="defaultModelSetting" :loop-workflow-mode="WorkflowMode.ToolLoop" :workflow-mode="WorkflowMode.Tool" />
</WorkflowViewLayout>
</template>
Loading