- {@render selectItems(item.children)}
+ {#if item.children && item.children.length > 0}
+
+ {@render renderDefaultItems(item.children, depth + 1)}
{/if}
{/each}
-
{/snippet}
+{#snippet renderModelItems(items: SelectItem[])}
+ {#each items as group}
+ {#if group.selectable === false}
+
+ {#if group.icon}
+ {@html group.icon}
+ {/if}
+ {group.label}
+
+ {#each group.children || [] as model}
+
+ {/each}
+ {:else}
+
+ {/if}
+ {/each}
+{/snippet}
+
+{#snippet renderNestedItems(items: SelectItem[], depth = 0)}
+ {#each items as item}
+
+
+
+ {#if item.children && item.children.length > 0}
+
+ {@render renderNestedItems(item.children, depth + 1)}
+
+ {/if}
+ {/each}
+{/snippet}
-
-
+
+
diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte
index 3021833..836510a 100644
--- a/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte
+++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/ConfirmParameterItem.svelte
@@ -94,7 +94,7 @@
{#if param.refType === 'fixed'}
updateParamByEvent('value', event)} />
{:else if (param.refType !== 'input')}
-
{/if}
diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/RefParameterItem.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/RefParameterItem.svelte
index 266ff40..d29a562 100644
--- a/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/RefParameterItem.svelte
+++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/core/RefParameterItem.svelte
@@ -95,7 +95,7 @@
{#if param.refType === 'fixed'}
updateParamByEvent('value', event)} />
{:else if (param.refType !== 'input')}
-
{/if}
diff --git a/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/LLMNode.svelte b/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/LLMNode.svelte
index 114d882..76b9797 100644
--- a/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/LLMNode.svelte
+++ b/easyflow-ui-admin/packages/tinyflow-ui/src/components/nodes/LLMNode.svelte
@@ -29,7 +29,53 @@
let llmArray = $state
([]);
onMount(async () => {
const newLLMs = await options.provider?.llm?.();
- llmArray.push(...(newLLMs || []));
+
+ const isFlat = newLLMs?.every(item => !item.children);
+
+ if (isFlat && newLLMs && newLLMs.length > 0) {
+ const grouped = new Map();
+ for (const llm of newLLMs) {
+ // If it still has a slash, parse it; otherwise, check if there's a custom logic we can infer brand.
+ // In WorkflowDesign we pass `item.modelProvider?.providerName` via some other way, but here it's flat.
+ // Actually, the label is just the title now (e.g. 'deepseek-chat').
+ // Wait, LLMNode doesn't know the brand unless it's in the string or we modify WorkflowDesign to pass `brand`.
+ // Let's modify WorkflowDesign to pass `brand` instead.
+ let brand = (llm as any).brand || '其他';
+ let modelName = llm.label;
+
+ if (!grouped.has(brand)) {
+ grouped.set(brand, []);
+ }
+ grouped.get(brand)!.push({
+ ...llm,
+ label: modelName,
+ displayLabel: modelName // 外部选中时也只显示模型名称
+ });
+ }
+
+ const treeArray: SelectItem[] = [];
+ for (const [brand, models] of grouped) {
+ // Try to get a representative icon for the brand from its children
+ let groupIcon = undefined;
+ if (models.length > 0) {
+ const modelWithIcon = models.find(m => m.icon);
+ if (modelWithIcon) {
+ groupIcon = modelWithIcon.icon;
+ }
+ }
+
+ treeArray.push({
+ label: brand,
+ value: 'group_' + brand,
+ selectable: false,
+ icon: groupIcon,
+ children: models
+ });
+ }
+ llmArray.push(...treeArray);
+ } else {
+ llmArray.push(...(newLLMs || []));
+ }
});
const { updateNodeData } = useSvelteFlow();
@@ -116,7 +162,7 @@
模型设置
模型
-