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 @@ -16,7 +16,10 @@


class ChatNodeSerializer(serializers.Serializer):
model_id = serializers.CharField(required=True, label=_("Model id"))
model_id = serializers.CharField(required=False, allow_blank=True, allow_null=True, label=_("Model id"))
model_id_type = serializers.CharField(required=False, default='custom', label=_("Model id type"))
model_id_reference = serializers.ListField(required=False, child=serializers.CharField(), allow_empty=True,
label=_("Reference Field"))
system = serializers.CharField(required=False, allow_blank=True, allow_null=True,
label=_("Role Setting"))
prompt = serializers.CharField(required=True, label=_("Prompt word"))
Expand Down Expand Up @@ -58,7 +61,7 @@ def get_node_params_serializer_class(self) -> Type[serializers.Serializer]:
def _run(self):
if [WorkflowMode.KNOWLEDGE, WorkflowMode.KNOWLEDGE_LOOP, WorkflowMode.TOOL,
WorkflowMode.TOOL_LOOP].__contains__(
self.workflow_manage.flow.workflow_mode):
self.workflow_manage.flow.workflow_mode):
return self.execute(**self.node_params_serializer.data, **self.flow_params_serializer.data,
**{'history_chat_record': [], 'stream': True, 'chat_id': None, 'chat_record_id': None})
else:
Expand All @@ -67,6 +70,8 @@ def _run(self):
def execute(self, model_id, system, prompt, dialogue_number, history_chat_record, stream, chat_id,
chat_record_id,
model_params_setting=None,
model_id_type=None,
model_id_reference=None,
dialogue_type=None,
model_setting=None,
mcp_servers=None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ def save_context(self, details, workflow_manage):

def execute(self, model_id, system, prompt, dialogue_number, history_chat_record, stream, chat_id, chat_record_id,
model_params_setting=None,
model_id_type=None,
model_id_reference=None,
dialogue_type=None,
model_setting=None,
mcp_servers=None,
Expand All @@ -165,8 +167,20 @@ def execute(self, model_id, system, prompt, dialogue_number, history_chat_record
if dialogue_type is None:
dialogue_type = 'WORKFLOW'

if model_params_setting is None:
if model_id_type == 'reference' and model_id_reference:

reference_data = self.workflow_manage.get_reference_field(
model_id_reference[0],
model_id_reference[1:],
)

if reference_data and isinstance(reference_data, dict):
model_id = reference_data.get('model_id', model_id)
model_params_setting = reference_data.get('model_params_setting')

if model_params_setting is None and model_id:
model_params_setting = get_default_model_params_setting(model_id)

if model_setting is None:
model_setting = {'reasoning_content_enable': False, 'reasoning_content_end': '</think>',
'reasoning_content_start': '<think>'}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The provided code has several improvements and corrections to ensure its functionality:

  1. Model ID Type Handling: The logic to handle model_id_type and model_id_reference fields is enhanced. It checks if model_id_type is set to 'reference' and if model_id_reference is not empty before attempting to fetch reference data using the workflow manager.

  2. Default Model Parameters Setting Retrieval: If no model_params_setting is provided, it retrieves a default setting from the system for the given model_id. This addresses cases where a specific configuration might be required but was not explicitly passed.

  3. Comments and Consistency: A comment is added explaining that comments may need more context about what they represent after further development on this line.

These changes make the function more robust, cleaner, and adaptable based on various conditions encountered during execution.

Expand Down
4 changes: 0 additions & 4 deletions ui/src/workflow/common/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1050,10 +1050,6 @@ export const toolWorkflowLibNode = {
stepName: t('workflow.nodes.toolWorlflowNode.label','工作流工具'),
config: {
fields: [
{
label: t('common.result'),
value: 'result',
},
],
},
},
Expand Down
59 changes: 43 additions & 16 deletions ui/src/workflow/nodes/ai-chat-node/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@
>
<el-form-item
:label="$t('views.application.form.aiModel.label')"
prop="model_id"
:prop="chat_data.model_id_type === 'reference' ? 'model_id_reference' : 'model_id'"
:rules="{
required: true,
message: $t('views.application.form.aiModel.placeholder'),
message: chat_data.model_id_type === 'reference' ? $t('workflow.variable.placeholder') : $t('views.application.form.aiModel.placeholder'),
trigger: 'change',
}"
>
Expand All @@ -28,7 +28,27 @@
}}<span class="color-danger">*</span></span
>
</div>

<el-select v-model="chat_data.model_id_type" :teleported="false" size="small" style="width: 85px" @change="chat_data.model_id_reference = []">
<el-option :label="$t('workflow.variable.Referencing')" value="reference" />
<el-option :label="$t('common.custom')" value="custom" />
</el-select>
</div>
</template>
<div class="flex-between w-full" v-if="chat_data.model_id_type !== 'reference'">
<div>
<ModelSelect
@change="model_change"
@wheel="wheel"
:teleported="false"
v-model="chat_data.model_id"
:placeholder="$t('views.application.form.aiModel.placeholder')"
:options="modelOptions"
@submitModel="getSelectModel"
showFooter
:model-type="'LLM'"
></ModelSelect>
</div>
<div class="ml-8">
<el-button
:disabled="!chat_data.model_id"
type="primary"
Expand All @@ -39,18 +59,15 @@
<AppIcon iconName="app-setting"></AppIcon>
</el-button>
</div>
</template>
<ModelSelect
@change="model_change"
@wheel="wheel"
:teleported="false"
v-model="chat_data.model_id"
:placeholder="$t('views.application.form.aiModel.placeholder')"
:options="modelOptions"
@submitModel="getSelectModel"
showFooter
:model-type="'LLM'"
></ModelSelect>
</div>
<NodeCascader
v-else
ref="nodeCascaderRef"
:nodeModel="nodeModel"
class="w-full"
:placeholder="$t('workflow.variable.placeholder')"
v-model="chat_data.model_id_reference"
/>
</el-form-item>

<el-form-item>
Expand All @@ -71,7 +88,7 @@
type="primary"
link
@click="openGeneratePromptDialog(chat_data.model_id)"
:disabled="!chat_data.model_id"
:disabled="chat_data.model_id_type === 'reference' || !chat_data.model_id"
>
<AppIcon iconName="app-generate-star"></AppIcon>
</el-button>
Expand Down Expand Up @@ -458,6 +475,7 @@
<script setup lang="ts">
import { cloneDeep, set, groupBy } from 'lodash'
import NodeContainer from '@/workflow/common/NodeContainer.vue'
import NodeCascader from '@/workflow/common/NodeCascader.vue'
import type { FormInstance } from 'element-plus'
import { ref, computed, onMounted, inject, reactive } from 'vue'
import { isLastNode } from '@/workflow/common/data'
Expand Down Expand Up @@ -532,6 +550,8 @@ const collapseData = reactive({

const form = {
model_id: '',
model_id_type: 'custom',
model_id_reference: [],
system: '',
prompt: defaultPrompt,
dialogue_number: 1,
Expand All @@ -556,6 +576,12 @@ const chat_data = computed({
reasoning_content_enable: false,
})
}
if (!props.nodeModel.properties.node_data.model_id_type) {
set(props.nodeModel.properties.node_data, 'model_id_type', 'custom')
}
if (!props.nodeModel.properties.node_data.model_id_reference) {
set(props.nodeModel.properties.node_data, 'model_id_reference', [])
}
return props.nodeModel.properties.node_data
} else {
set(props.nodeModel.properties, 'node_data', form)
Expand All @@ -573,6 +599,7 @@ const aiChatNodeFormRef = ref<FormInstance>()

const modelOptions = ref<any>(null)
const AIModeParamSettingDialogRef = ref<InstanceType<typeof AIModeParamSettingDialog>>()
const nodeCascaderRef = ref()
const ReasoningParamSettingDialogRef = ref<InstanceType<typeof ReasoningParamSettingDialog>>()
const validate = () => {
return aiChatNodeFormRef.value?.validate().catch((err) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Replace set(appState.chat, "node_model_data.reasoning_info", {}); with appState.node_model_data.reasoning_info = {};.
  • Adjust the conditional logic in the AI Chat Mode Param Setting Dialog to handle different conditions as needed.

Expand Down
3 changes: 3 additions & 0 deletions ui/src/workflow/nodes/tool-workflow-lib-node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ class ToolWorkflowLibNode extends AppNode {
constructor(props: any) {
super(props, ToolWorkflowLibNodeVue)
}
getConfig(props: any) {
return props.model.properties.config
}
}
export default {
type: 'tool-workflow-lib-node',
Expand Down
22 changes: 10 additions & 12 deletions ui/src/workflow/nodes/tool-workflow-lib-node/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,26 +150,21 @@ const update_field = () => {
loadSharedApi({ type: 'tool', systemType: apiType.value })
.getToolById(props.nodeModel.properties.node_data.tool_lib_id)
.then((ok: any) => {
console.log('ssss', ok.data)

const workflowNodes = ok.data?.work_flow?.nodes || []
const baseNode = workflowNodes.find((n: any) => n.type === 'tool-base-node')

if (baseNode) {
const new_input_list = baseNode.properties.user_input_field_list || []
const new_output_list = baseNode.properties.user_output_field_list || []

let config_field_list: any[] = []
if (new_output_list.length > 0) {
config_field_list = new_output_list.map((item: any) => ({
label: item.label,
value: item.field,
}))
}
const old_config_fields = props.nodeModel.properties.config?.fields || []
const config_field_list = new_output_list.map((item: any) => {
const old = old_config_fields.find((o: any) => o.value === item.field)
return old ? JSON.parse(JSON.stringify(old)) : { label: item.label, value: item.field }
})

const input_title = baseNode.properties.user_input_config?.title
const output_title = baseNode.properties.user_output_config?.title

const old_input_list = props.nodeModel.properties.node_data.input_field_list || []
const merged_input_list = new_input_list.map((item: any) => {
const find_field = old_input_list.find((old_item: any) => old_item.field === item.field)
Expand All @@ -185,11 +180,14 @@ const update_field = () => {
})

set(props.nodeModel.properties.node_data, 'input_field_list', merged_input_list)
set(props.nodeModel.properties.config, 'fields', config_field_list)
set(props.nodeModel.properties, 'config', {
fields: config_field_list,
output_title: output_title,
})
set(props.nodeModel.properties.node_data, 'input_title', input_title)
set(props.nodeModel.properties.config, 'output_title', output_title)
}
set(props.nodeModel.properties, 'status', ok.data.is_active ? 200 : 500)
props.nodeModel.clear_next_node_field(true)
})
.catch(() => {
set(props.nodeModel.properties, 'status', 500)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several areas where improvements could be made in the provided code:

  1. Simplified config_field_list Creation: The current method of creating config_field_list uses nested ternary operators which can make it difficult to read and maintain. It's more readable to use plain JavaScript methods.

  2. Object Shallow Copying for Existing Fields: Instead of using JSON.parse(JSON.stringify(...)) when updating existing fields, we can directly modify them since they are arrays. However, this requires careful handling to ensure no unintended side effects.

  3. Clear Next Node Field Execution: Ensure that props.nodeModel.clear_next_node_field(true) is called consistently throughout the function.

Here’s an optimized version of the code with these considerations:

const update_field = () => {
    loadSharedApi({ type: 'tool', systemType: apiType.value })
        .getToolById(props.nodeModel.properties.node_data.tool_lib_id)
        .then((ok: any) => {
            const workflowNodes = ok.data?.work_flow?.nodes || [];
            const baseNode = workflowNodes.find((n: any) => n.type === 'tool-base-node');

            if (baseNode) {
                const new_input_list = baseNode.properties.user_input_field_list || [];
                const new_output_list = baseNode.properties.user_output_field_list || [];

                // Create config_fields list from new_output_list
                let config_field_list = new_output_list.map(item => ({ label: item.label, value: item.field }));

                // Update original node data with new lists
                const old_input_list = props.nodeModel.properties.node_data.input_field_list || [];
                const merged_input_list = new_input_list.map(item => {
                    const findField = old_input_list.find(oldItem => oldItem.field === item.field);
                    return findField || item;
                });
                set(props.nodeModel.properties.node_data, 'input_field_list', merged_input_list);

                // Handle merging config fields
                const oldConfigFields = props.nodeModel.properties.config.fields || [];
                config_field_list.forEach(newField => {
                    const existingIndex = oldConfigFields.findIndex(ocf => ocf.value === newField.value);
                    if (existingIndex !== -1) {
                        // If field already exists, do nothing or merge properties accordingly
                        config_field_list[existingIndex] = { ...oldConfigFields[existingIndex], ...newField };
                    } else {
                        // Add new field if not found
                        config_field_list.push(newField);
                    }
                });

                const input_title = baseNode.properties.user_input_config?.title;
                const output_title = baseNode.properties.user_output_config?.title;

                set(props.nodeModel.properties.node_data, 'input_title', input_title);
                set(props.nodeModel.properties.config, 'output_title', output_title);

                // Clear next node field(s), assuming clear_next_node_field accepts a boolean condition
                props.nodeModel.clear_next_node_field(true);
                
                set(props.nodeModel.properties, 'status', ok.data.is_active ? 200 : 500);
            }

            // Set fallback status on failure
        }).catch(() => {
            set(props.nodeModel.properties, 'status', 500);
        });
};

Key Changes:

  • Simplified config_field_list creation.
  • Directly updated non-existing fields in merge_input_list.
  • Merged existing config fields while preserving uniqueness.
  • Ensured clear_next_node_field execution without modification risk.

Make sure to test this revised version thoroughly in your application environment to validate its functionality.

Expand Down
Loading