vue-agent-start 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (169) hide show
  1. package/package.json +30 -0
  2. package/pnpm-workspace.yaml +3 -0
  3. package/src/agent-flow/adapter/backend.ts +99 -0
  4. package/src/agent-flow/components/ChatIframePanel.vue +773 -0
  5. package/src/agent-flow/components/DatasetItemCard.vue +313 -0
  6. package/src/agent-flow/components/MemoryWindow.vue +104 -0
  7. package/src/agent-flow/components/PromptEditor.vue +804 -0
  8. package/src/agent-flow/components/PromptEditorTagPanel.vue +460 -0
  9. package/src/agent-flow/components/SvgIcon.vue +32 -0
  10. package/src/agent-flow/components/ToolItemCard.vue +169 -0
  11. package/src/agent-flow/components/VariableCard.vue +161 -0
  12. package/src/agent-flow/components/VariableSelector.vue +162 -0
  13. package/src/agent-flow/components/chat-iframe-types.ts +35 -0
  14. package/src/agent-flow/components/stubs/DatasetChooser.vue +70 -0
  15. package/src/agent-flow/components/stubs/Embedding.vue +22 -0
  16. package/src/agent-flow/components/stubs/ModelSelect.vue +24 -0
  17. package/src/agent-flow/components/stubs/RestfulSelectCard.vue +24 -0
  18. package/src/agent-flow/components/stubs/ToolChooser.vue +96 -0
  19. package/src/agent-flow/components/stubs/TriggersItemCard.vue +126 -0
  20. package/src/agent-flow/components/stubs/VariableModal.vue +115 -0
  21. package/src/agent-flow/index.ts +73 -0
  22. package/src/agent-flow/stores/workflow.ts +72 -0
  23. package/src/agent-flow/utils/langUtils.ts +173 -0
  24. package/src/agent-flow/workflow/Ability.vue +65 -0
  25. package/src/agent-flow/workflow/AuthorizationItem.vue +101 -0
  26. package/src/agent-flow/workflow/ConversationVar.vue +42 -0
  27. package/src/agent-flow/workflow/CustomEdge.vue +94 -0
  28. package/src/agent-flow/workflow/EnvironmentVar.vue +40 -0
  29. package/src/agent-flow/workflow/FlowDesigner.vue +2802 -0
  30. package/src/agent-flow/workflow/Icon.vue +179 -0
  31. package/src/agent-flow/workflow/NodeConfig.vue +509 -0
  32. package/src/agent-flow/workflow/NodeConfigCard.vue +460 -0
  33. package/src/agent-flow/workflow/NodeHandle.vue +147 -0
  34. package/src/agent-flow/workflow/NodeHeaderToolbar.vue +77 -0
  35. package/src/agent-flow/workflow/NodeHoverToolbar.vue +176 -0
  36. package/src/agent-flow/workflow/OutputItemCard.vue +668 -0
  37. package/src/agent-flow/workflow/ParamTableItem.vue +200 -0
  38. package/src/agent-flow/workflow/StructTable.vue +202 -0
  39. package/src/agent-flow/workflow/VarInsertField.vue +517 -0
  40. package/src/agent-flow/workflow/VarSelectField.vue +223 -0
  41. package/src/agent-flow/workflow/VariableSelectorItem.vue +48 -0
  42. package/src/agent-flow/workflow/WfField.vue +206 -0
  43. package/src/agent-flow/workflow/_config-base.css +470 -0
  44. package/src/agent-flow/workflow/composables/useNode.js +55 -0
  45. package/src/agent-flow/workflow/index.vue +53 -0
  46. package/src/agent-flow/workflow/nodeCard/AgentNodeCard.vue +180 -0
  47. package/src/agent-flow/workflow/nodeCard/AnswerNodeCard.vue +65 -0
  48. package/src/agent-flow/workflow/nodeCard/ClassifierCard.vue +152 -0
  49. package/src/agent-flow/workflow/nodeCard/CodeNodeCard.vue +139 -0
  50. package/src/agent-flow/workflow/nodeCard/ConditionNodeCard.vue +323 -0
  51. package/src/agent-flow/workflow/nodeCard/DocumentExtractorCard.vue +83 -0
  52. package/src/agent-flow/workflow/nodeCard/EndNodeCard.vue +123 -0
  53. package/src/agent-flow/workflow/nodeCard/HttpNodeCard.vue +451 -0
  54. package/src/agent-flow/workflow/nodeCard/HumanInputCard.vue +152 -0
  55. package/src/agent-flow/workflow/nodeCard/IterationCard.vue +66 -0
  56. package/src/agent-flow/workflow/nodeCard/KnowledgeRetrievalCard.vue +48 -0
  57. package/src/agent-flow/workflow/nodeCard/LLMNodeCard.vue +206 -0
  58. package/src/agent-flow/workflow/nodeCard/ListOperatorCard.vue +188 -0
  59. package/src/agent-flow/workflow/nodeCard/ParameterExtractorCard.vue +352 -0
  60. package/src/agent-flow/workflow/nodeCard/ServiceApiNodeCard.vue +188 -0
  61. package/src/agent-flow/workflow/nodeCard/StartNodeCard.vue +216 -0
  62. package/src/agent-flow/workflow/nodeCard/VariableAssignerCard.vue +125 -0
  63. package/src/agent-flow/workflow/nodeCard/VariableNodeCard.vue +121 -0
  64. package/src/agent-flow/workflow/nodes/AgentNode.vue +122 -0
  65. package/src/agent-flow/workflow/nodes/AnswerNode.vue +99 -0
  66. package/src/agent-flow/workflow/nodes/ClassifierNode.vue +199 -0
  67. package/src/agent-flow/workflow/nodes/CodeNode.vue +152 -0
  68. package/src/agent-flow/workflow/nodes/ConditionNode.vue +232 -0
  69. package/src/agent-flow/workflow/nodes/DocumentExtractorNode.vue +96 -0
  70. package/src/agent-flow/workflow/nodes/EndNode.vue +119 -0
  71. package/src/agent-flow/workflow/nodes/FileUploadNode.vue +97 -0
  72. package/src/agent-flow/workflow/nodes/HttpNode.vue +204 -0
  73. package/src/agent-flow/workflow/nodes/HumanInputNode.vue +110 -0
  74. package/src/agent-flow/workflow/nodes/IterationNode.vue +98 -0
  75. package/src/agent-flow/workflow/nodes/KnowledgeRetrievalNode.vue +253 -0
  76. package/src/agent-flow/workflow/nodes/LLMNode.vue +134 -0
  77. package/src/agent-flow/workflow/nodes/ListOperatorNode.vue +111 -0
  78. package/src/agent-flow/workflow/nodes/LoopNode.vue +94 -0
  79. package/src/agent-flow/workflow/nodes/ParameterExtractorNode.vue +147 -0
  80. package/src/agent-flow/workflow/nodes/ServiceApiNode.vue +161 -0
  81. package/src/agent-flow/workflow/nodes/StartNode.vue +199 -0
  82. package/src/agent-flow/workflow/nodes/TemplateNode.vue +103 -0
  83. package/src/agent-flow/workflow/nodes/UserInputNode.vue +92 -0
  84. package/src/agent-flow/workflow/nodes/VariableAssignerNode.vue +145 -0
  85. package/src/agent-flow/workflow/nodes/VariableNode.vue +130 -0
  86. package/src/agent-flow/workflow/nodes/_node-base.css +338 -0
  87. package/src/agent-flow/workflow/utils/node_card_form.ts +335 -0
  88. package/src/agent-flow/workflow/utils/node_config.ts +63 -0
  89. package/src/agent-flow/workflow/utils/workflow_utils.ts +151 -0
  90. package/src/agent-studio/adapters/springAgentStart.ts +390 -0
  91. package/src/agent-studio/api/index.ts +1 -0
  92. package/src/agent-studio/api/types.ts +173 -0
  93. package/src/agent-studio/components/AgentApiDocs.vue +500 -0
  94. package/src/agent-studio/components/AgentAppsPage.vue +1601 -0
  95. package/src/agent-studio/components/AgentCardGrid.vue +259 -0
  96. package/src/agent-studio/components/AgentChatPage.vue +553 -0
  97. package/src/agent-studio/components/AgentDebugPanel.vue +350 -0
  98. package/src/agent-studio/components/AgentLogsPanel.vue +391 -0
  99. package/src/agent-studio/components/AgentMonitorPanel.vue +204 -0
  100. package/src/agent-studio/components/AgentOrchestrate.vue +505 -0
  101. package/src/agent-studio/components/AgentPromptEditor.vue +237 -0
  102. package/src/agent-studio/components/AgentStudioShell.vue +227 -0
  103. package/src/agent-studio/components/AgentToolsPanel.vue +394 -0
  104. package/src/agent-studio/components/AgentVariablesPanel.vue +205 -0
  105. package/src/agent-studio/components/ApiKeyManager.vue +251 -0
  106. package/src/agent-studio/components/AppDesignDrawer.vue +3391 -0
  107. package/src/agent-studio/components/CreateAppModal.vue +737 -0
  108. package/src/agent-studio/components/SparkChart.vue +200 -0
  109. package/src/agent-studio/components/VariableEditorModal.vue +499 -0
  110. package/src/agent-studio/composables/useAgentStudio.ts +347 -0
  111. package/src/agent-studio/index.ts +60 -0
  112. package/src/agent-studio/panels/DrawerFlowDesigner.vue +203 -0
  113. package/src/agent-studio/panels/LogAnnotationPanel.vue +490 -0
  114. package/src/agent-studio/panels/MonitorPanel.vue +535 -0
  115. package/src/agent-studio/types.ts +242 -0
  116. package/src/index.ts +155 -0
  117. package/src/knowledge-hub/adapters/springAgentStart.ts +472 -0
  118. package/src/knowledge-hub/components/AddDocumentsWizard.vue +1452 -0
  119. package/src/knowledge-hub/components/CreateDatasetWizard.vue +1723 -0
  120. package/src/knowledge-hub/components/DatasetCardGrid.vue +467 -0
  121. package/src/knowledge-hub/components/DatasetDetailDrawer.vue +888 -0
  122. package/src/knowledge-hub/components/DatasetPicker.vue +65 -0
  123. package/src/knowledge-hub/components/DatasetPickerModal.vue +526 -0
  124. package/src/knowledge-hub/components/DatasetSettingsPanel.vue +908 -0
  125. package/src/knowledge-hub/components/DatasetSidebar.vue +781 -0
  126. package/src/knowledge-hub/components/DocumentChunksView.vue +802 -0
  127. package/src/knowledge-hub/components/DocumentTable.vue +552 -0
  128. package/src/knowledge-hub/components/HitTestingPanel.vue +74 -0
  129. package/src/knowledge-hub/components/KnowledgeApp.vue +66 -0
  130. package/src/knowledge-hub/components/KnowledgeHubApp.vue +504 -0
  131. package/src/knowledge-hub/components/RecallTestingPanelV2.vue +515 -0
  132. package/src/knowledge-hub/components/RetrievalConfigPopover.vue +270 -0
  133. package/src/knowledge-hub/components/RetrievalMethodPicker.vue +547 -0
  134. package/src/knowledge-hub/components/RetrievedList.vue +24 -0
  135. package/src/knowledge-hub/components/internal/KhDialog.vue +195 -0
  136. package/src/knowledge-hub/composables/useKnowledge.ts +89 -0
  137. package/src/knowledge-hub/i18n/index.ts +2 -0
  138. package/src/knowledge-hub/i18n/messages.ts +422 -0
  139. package/src/knowledge-hub/i18n/useKhI18n.ts +107 -0
  140. package/src/knowledge-hub/index.ts +46 -0
  141. package/src/knowledge-hub/styles/index.css +4 -0
  142. package/src/knowledge-hub/styles/tokens.css +138 -0
  143. package/src/knowledge-hub/types/api.ts +213 -0
  144. package/src/knowledge-hub/types/dataset.ts +88 -0
  145. package/src/knowledge-hub/types/document.ts +45 -0
  146. package/src/knowledge-hub/types/index.ts +9 -0
  147. package/src/knowledge-hub/types/retrieval.ts +46 -0
  148. package/src/provider-hub/components/CredentialForm.vue +103 -0
  149. package/src/provider-hub/components/DefaultModelsPanel.vue +270 -0
  150. package/src/provider-hub/components/GroupedModelSelect.vue +445 -0
  151. package/src/provider-hub/components/ModelCardGrid.vue +332 -0
  152. package/src/provider-hub/components/ModelParameterDrawer.vue +739 -0
  153. package/src/provider-hub/components/ModelPickerPopover.vue +1282 -0
  154. package/src/provider-hub/components/ProviderApp.vue +159 -0
  155. package/src/provider-hub/components/ProviderCredentialModal.vue +321 -0
  156. package/src/provider-hub/components/ProviderGallery.vue +131 -0
  157. package/src/provider-hub/components/ProviderHubShell.vue +1992 -0
  158. package/src/provider-hub/components/ProviderIcon.vue +130 -0
  159. package/src/provider-hub/composables/useProviderHub.ts +358 -0
  160. package/src/provider-hub/index.ts +43 -0
  161. package/src/provider-hub/svg/MiniMax.svg +1 -0
  162. package/src/provider-hub/svg/Volcengine.svg +1 -0
  163. package/src/provider-hub/svg/Zhipu.svg +1 -0
  164. package/src/provider-hub/svg/deepseek.svg +1 -0
  165. package/src/provider-hub/svg/moonshot.svg +1 -0
  166. package/src/provider-hub/svg/openai.svg +1 -0
  167. package/src/provider-hub/svg/qwen.svg +1 -0
  168. package/src/provider-hub/svg/siliconflow.svg +1 -0
  169. package/src/provider-hub/types.ts +256 -0
@@ -0,0 +1,253 @@
1
+ <script setup>
2
+ import { computed, ref } from 'vue';
3
+
4
+ import workflow_utils from '@/workflow/utils/workflow_utils';
5
+
6
+ import Icon from '../Icon.vue';
7
+ import NodeHandle from '../NodeHandle.vue';
8
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
9
+
10
+ const props = defineProps({
11
+ id: String,
12
+ data: {
13
+ type: Object,
14
+ default: () => ({
15
+ label: '知识检索',
16
+ description: '从知识库中检索相关文档',
17
+ queryVariableSelector: [],
18
+ dataset: { datasets: [] },
19
+ config: { top_k: 3 },
20
+ }),
21
+ },
22
+ });
23
+
24
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
25
+
26
+ const isHovered = ref(false);
27
+
28
+ const onMouseEnter = () => (isHovered.value = true);
29
+ const onMouseLeave = () => (isHovered.value = false);
30
+ const duplicateNode = () => emit('duplicate', props.id);
31
+ const deleteNode = () => emit('delete', props.id);
32
+ const onConnectionPlusClick = (event) => {
33
+ emit('connection-plus-click', event, props.id);
34
+ };
35
+
36
+ const truncateText = (text, maxLength) => {
37
+ if (!text) return '';
38
+ return text.length > maxLength
39
+ ? `${text.slice(0, Math.max(0, maxLength))}...`
40
+ : text;
41
+ };
42
+
43
+ const getQueryVarLabel = (variableSelector) =>
44
+ workflow_utils.getVariableLabel(variableSelector);
45
+
46
+ const datasets = computed(() => props.data?.dataset?.datasets ?? []);
47
+ const queryVar = computed(() => props.data?.queryVariableSelector ?? []);
48
+ const topK = computed(() => props.data?.config?.top_k ?? 3);
49
+ const isDynamic = computed(() => props.data?.dataset?.dynamic === true);
50
+ </script>
51
+
52
+ <template>
53
+ <div
54
+ class="wf-node knowledge-node"
55
+ @mouseenter="onMouseEnter"
56
+ @mouseleave="onMouseLeave"
57
+ >
58
+ <NodeHoverToolbar
59
+ v-if="isHovered"
60
+ node-type="knowledge_retrieval"
61
+ @duplicate="duplicateNode"
62
+ @delete="deleteNode"
63
+ />
64
+
65
+ <div class="wf-node-header">
66
+ <div class="wf-node-icon">
67
+ <Icon name="knowledge" />
68
+ </div>
69
+ <div class="wf-node-info">
70
+ <div class="wf-node-title">{{ data.label }}</div>
71
+ <div class="wf-node-subtitle">
72
+ <span>{{ isDynamic ? '动态数据集' : `已选 ${datasets.length} 个` }}</span>
73
+ <span class="knowledge-topk-chip">top {{ topK }}</span>
74
+ </div>
75
+ </div>
76
+ </div>
77
+
78
+ <div class="wf-node-content">
79
+ <div v-if="queryVar.length > 0" class="knowledge-query">
80
+ <span class="knowledge-query-label">
81
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12">
82
+ <path fill="currentColor" d="M15.5 14h-.79l-.28-.27a6.5 6.5 0 0 0 1.48-5.34c-.47-2.78-2.79-5-5.59-5.34a6.505 6.505 0 0 0-7.27 7.27c.34 2.8 2.56 5.12 5.34 5.59a6.5 6.5 0 0 0 5.34-1.48l.27.28v.79l4.25 4.25c.41.41 1.08.41 1.49 0c.41-.41.41-1.08 0-1.49L15.5 14zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5S14 7.01 14 9.5S11.99 14 9.5 14z"/>
83
+ </svg>
84
+ 查询
85
+ </span>
86
+ <span class="knowledge-query-value">
87
+ {{ getQueryVarLabel(queryVar) }}
88
+ </span>
89
+ </div>
90
+
91
+ <div v-if="datasets.length > 0" class="knowledge-dataset-list">
92
+ <div
93
+ v-for="item in datasets"
94
+ :key="item.id"
95
+ class="knowledge-dataset-row"
96
+ >
97
+ <span class="knowledge-dataset-icon">
98
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="14" height="14">
99
+ <path fill="currentColor" d="M12 3C7.58 3 4 4.79 4 7v10c0 2.21 3.59 4 8 4s8-1.79 8-4V7c0-2.21-3.58-4-8-4m6 14c0 .5-2.13 2-6 2s-6-1.5-6-2v-2.23c1.61.78 3.72 1.23 6 1.23s4.39-.45 6-1.23V17m0-5c0 .5-2.13 2-6 2s-6-1.5-6-2V9.77c1.61.78 3.72 1.23 6 1.23s4.39-.45 6-1.23V12m-6-3c-3.87 0-6-1.5-6-2s2.13-2 6-2s6 1.5 6 2s-2.13 2-6 2Z"/>
100
+ </svg>
101
+ </span>
102
+ <span class="knowledge-dataset-name" :title="item.name">
103
+ {{ truncateText(item.name, 20) }}
104
+ </span>
105
+ <span v-if="item.tags && item.tags.length" class="knowledge-dataset-tag">
106
+ {{ item.tags[0] }}
107
+ </span>
108
+ </div>
109
+ </div>
110
+ <div v-else-if="isDynamic" class="knowledge-dynamic-hint">
111
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="12" height="12">
112
+ <path fill="currentColor" d="M13 3a9 9 0 0 0-9 9H1l3.89 3.89l.07.14L9 12H6c0-3.87 3.13-7 7-7s7 3.13 7 7s-3.13 7-7 7c-1.93 0-3.68-.79-4.94-2.06l-1.42 1.42A8.954 8.954 0 0 0 13 21a9 9 0 0 0 0-18Zm-1 5v5l4.28 2.54l.72-1.21l-3.5-2.08V8H12Z"/>
113
+ </svg>
114
+ <span>数据集由运行时变量决定</span>
115
+ </div>
116
+ <div v-else class="wf-node-empty">
117
+ <span class="wf-node-empty-text">尚未选择知识库</span>
118
+ </div>
119
+ </div>
120
+
121
+ <NodeHandle
122
+ :id="id"
123
+ type="target"
124
+ position="Left"
125
+ :is-hovered="isHovered"
126
+ class-name="flow-node-handle-left"
127
+ :style="{ background: '#14b8a6', border: '2px solid #ffffff' }"
128
+ />
129
+
130
+ <NodeHandle
131
+ :id="id"
132
+ type="source"
133
+ position="Right"
134
+ :is-hovered="isHovered"
135
+ class-name="flow-node-handle-right"
136
+ :style="{ background: '#14b8a6', border: '2px solid #ffffff' }"
137
+ @connection-plus-click="onConnectionPlusClick"
138
+ />
139
+ </div>
140
+ </template>
141
+
142
+ <style scoped>
143
+ .knowledge-node {
144
+ --wf-accent: #14b8a6;
145
+ --wf-accent-hover: #0d9488;
146
+ }
147
+
148
+ .knowledge-topk-chip {
149
+ padding: 1px 6px;
150
+ font-size: 10px;
151
+ font-weight: 600;
152
+ color: color-mix(in srgb, var(--wf-accent) 90%, #000);
153
+ background: color-mix(in srgb, var(--wf-accent) 15%, transparent);
154
+ border-radius: 999px;
155
+ }
156
+
157
+ .knowledge-query {
158
+ display: flex;
159
+ align-items: center;
160
+ gap: 6px;
161
+ margin-bottom: 8px;
162
+ padding: 6px 8px;
163
+ background: color-mix(in srgb, var(--wf-accent) 7%, transparent);
164
+ border: 1px solid color-mix(in srgb, var(--wf-accent) 25%, transparent);
165
+ border-radius: 6px;
166
+ font-size: 11px;
167
+ }
168
+
169
+ .knowledge-query-label {
170
+ display: inline-flex;
171
+ align-items: center;
172
+ gap: 4px;
173
+ flex: none;
174
+ color: color-mix(in srgb, var(--wf-accent) 85%, #000);
175
+ font-weight: 500;
176
+ }
177
+
178
+ .knowledge-query-value {
179
+ flex: 1;
180
+ min-width: 0;
181
+ color: #1f2937;
182
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
183
+ overflow: hidden;
184
+ text-overflow: ellipsis;
185
+ white-space: nowrap;
186
+ }
187
+
188
+ .knowledge-dataset-list {
189
+ display: flex;
190
+ flex-direction: column;
191
+ gap: 4px;
192
+ }
193
+
194
+ .knowledge-dataset-row {
195
+ display: flex;
196
+ align-items: center;
197
+ gap: 8px;
198
+ padding: 5px 8px;
199
+ font-size: 11px;
200
+ background: #ffffff;
201
+ border: 1px solid #e5e7eb;
202
+ border-radius: 6px;
203
+ transition: border-color 0.15s, background 0.15s;
204
+ }
205
+
206
+ .knowledge-dataset-row:hover {
207
+ border-color: var(--wf-accent);
208
+ background: color-mix(in srgb, var(--wf-accent) 5%, #ffffff);
209
+ }
210
+
211
+ .knowledge-dataset-icon {
212
+ display: inline-flex;
213
+ align-items: center;
214
+ justify-content: center;
215
+ flex: none;
216
+ width: 20px;
217
+ height: 20px;
218
+ color: var(--wf-accent);
219
+ background: color-mix(in srgb, var(--wf-accent) 12%, transparent);
220
+ border-radius: 4px;
221
+ }
222
+
223
+ .knowledge-dataset-name {
224
+ flex: 1;
225
+ min-width: 0;
226
+ overflow: hidden;
227
+ color: #1f2937;
228
+ text-overflow: ellipsis;
229
+ white-space: nowrap;
230
+ font-weight: 500;
231
+ }
232
+
233
+ .knowledge-dataset-tag {
234
+ flex: none;
235
+ padding: 1px 6px;
236
+ font-size: 10px;
237
+ color: #6b7280;
238
+ background: #f3f4f6;
239
+ border-radius: 3px;
240
+ }
241
+
242
+ .knowledge-dynamic-hint {
243
+ display: flex;
244
+ align-items: center;
245
+ gap: 6px;
246
+ padding: 8px 10px;
247
+ font-size: 11px;
248
+ color: color-mix(in srgb, var(--wf-accent) 85%, #000);
249
+ background: color-mix(in srgb, var(--wf-accent) 6%, transparent);
250
+ border: 1px dashed color-mix(in srgb, var(--wf-accent) 40%, transparent);
251
+ border-radius: 6px;
252
+ }
253
+ </style>
@@ -0,0 +1,134 @@
1
+ <script setup>
2
+ import { ref } from 'vue';
3
+
4
+ import Icon from '../Icon.vue';
5
+ import NodeHandle from '../NodeHandle.vue';
6
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
7
+
8
+ const props = defineProps({
9
+ id: String,
10
+ data: {
11
+ type: Object,
12
+ default: () => ({
13
+ label: 'LLM',
14
+ description: '大语言模型节点',
15
+ config: {
16
+ model: 'gpt-3.5-turbo',
17
+ temperature: 0.7,
18
+ max_tokens: 1000,
19
+ prompt: '',
20
+ },
21
+ }),
22
+ },
23
+ });
24
+
25
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
26
+
27
+ const isRunning = ref(false);
28
+ const showMetrics = ref(true);
29
+ const isHovered = ref(false);
30
+
31
+ const onMouseEnter = () => {
32
+ isHovered.value = true;
33
+ };
34
+
35
+ const onMouseLeave = () => {
36
+ // 保持 toolbar 常显,等悬停完再统一处理
37
+ };
38
+
39
+ const duplicateNode = () => {
40
+ emit('duplicate', props.id);
41
+ };
42
+
43
+ const deleteNode = () => {
44
+ emit('delete', props.id);
45
+ };
46
+
47
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
48
+ emit('connection-plus-click', event, nodeId, handleId);
49
+ };
50
+
51
+ const truncateText = (text, maxLength) => {
52
+ if (!text) return '';
53
+ return text.length > maxLength
54
+ ? `${text.slice(0, Math.max(0, maxLength))}...`
55
+ : text;
56
+ };
57
+ </script>
58
+
59
+ <template>
60
+ <div
61
+ class="wf-node llm-node"
62
+ @mouseenter="onMouseEnter"
63
+ @mouseleave="onMouseLeave"
64
+ >
65
+ <NodeHoverToolbar
66
+ v-if="isHovered"
67
+ node-type="llm"
68
+ @duplicate="duplicateNode"
69
+ @delete="deleteNode"
70
+ />
71
+
72
+ <div class="wf-node-header">
73
+ <div class="wf-node-icon">
74
+ <Icon name="llm" />
75
+ </div>
76
+ <div class="wf-node-info">
77
+ <div class="wf-node-title">{{ data.label }}</div>
78
+ <div class="wf-node-subtitle">
79
+ <div>{{ data.model?.provider }}</div>
80
+ <div>{{ data.model?.modelName || 'GPT-3.5-turbo' }}</div>
81
+ </div>
82
+ </div>
83
+ <div v-if="isRunning" class="wf-node-status">
84
+ <div class="wf-node-status-indicator wf-is-running"></div>
85
+ </div>
86
+ </div>
87
+
88
+ <div class="wf-node-content">
89
+ <div class="wf-node-description">{{ data.description }}</div>
90
+ <div v-if="data.config?.prompt" class="wf-node-config-preview">
91
+ <div class="wf-node-config-label">提示词预览</div>
92
+ <div class="wf-node-config-value">
93
+ {{ truncateText(data.config.prompt, 50) }}
94
+ </div>
95
+ </div>
96
+ </div>
97
+
98
+ <div v-if="showMetrics" class="wf-node-metrics">
99
+ <div class="wf-node-metric">
100
+ <span class="wf-node-metric-label">温度</span>
101
+ <span class="wf-node-metric-value">{{ data.config?.temperature ?? 0.7 }}</span>
102
+ </div>
103
+ <div class="wf-node-metric">
104
+ <span class="wf-node-metric-label">最大令牌</span>
105
+ <span class="wf-node-metric-value">{{ data.config?.max_tokens ?? 1000 }}</span>
106
+ </div>
107
+ </div>
108
+
109
+ <NodeHandle
110
+ :id="id"
111
+ type="target"
112
+ position="Left"
113
+ class-name="flow-node-handle-left"
114
+ :style="{ background: '#6366f1', border: '2px solid #ffffff' }"
115
+ />
116
+
117
+ <NodeHandle
118
+ :id="id"
119
+ type="source"
120
+ position="Right"
121
+ :is-hovered="isHovered"
122
+ class-name="flow-node-handle-right"
123
+ :style="{ background: '#6366f1', border: '2px solid #ffffff' }"
124
+ @connection-plus-click="onConnectionPlusClick"
125
+ />
126
+ </div>
127
+ </template>
128
+
129
+ <style scoped>
130
+ .llm-node {
131
+ --wf-accent: #6366f1;
132
+ --wf-accent-hover: #4f46e5;
133
+ }
134
+ </style>
@@ -0,0 +1,111 @@
1
+ <script setup lang="ts">
2
+ import { computed, ref } from 'vue';
3
+
4
+ import workflow_utils from '@/workflow/utils/workflow_utils';
5
+
6
+ import Icon from '../Icon.vue';
7
+ import NodeHandle from '../NodeHandle.vue';
8
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
9
+
10
+ const OP_LABELS: Record<string, string> = {
11
+ filter: '过滤',
12
+ map: '映射',
13
+ reduce: '归约',
14
+ slice: '截取',
15
+ sort: '排序',
16
+ reverse: '反转',
17
+ count: '计数',
18
+ };
19
+
20
+ const props = defineProps({
21
+ id: String,
22
+ data: {
23
+ type: Object,
24
+ default: () => ({
25
+ label: '列表操作',
26
+ description: '对列表变量做过滤/映射/排序等操作',
27
+ inputVariableSelector: [],
28
+ operation: 'filter',
29
+ }),
30
+ },
31
+ });
32
+
33
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
34
+
35
+ const isHovered = ref(false);
36
+
37
+ const onMouseEnter = () => (isHovered.value = true);
38
+ const onMouseLeave = () => (isHovered.value = false);
39
+ const duplicateNode = () => emit('duplicate', props.id);
40
+ const deleteNode = () => emit('delete', props.id);
41
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
42
+ emit('connection-plus-click', event, nodeId, handleId);
43
+ };
44
+
45
+ const inputLabel = computed(() =>
46
+ workflow_utils.getVariableLabel(props.data.inputVariableSelector || []),
47
+ );
48
+ const opLabel = computed(
49
+ () => OP_LABELS[props.data.operation] || props.data.operation || '未选择',
50
+ );
51
+ </script>
52
+
53
+ <template>
54
+ <div
55
+ class="wf-node list-operator-node"
56
+ @mouseenter="onMouseEnter"
57
+ @mouseleave="onMouseLeave"
58
+ >
59
+ <NodeHoverToolbar
60
+ v-if="isHovered"
61
+ node-type="list_operator"
62
+ @duplicate="duplicateNode"
63
+ @delete="deleteNode"
64
+ />
65
+
66
+ <div class="wf-node-header">
67
+ <div class="wf-node-icon">
68
+ <Icon name="variable" />
69
+ </div>
70
+ <div class="wf-node-info">
71
+ <div class="wf-node-title">{{ data.label }}</div>
72
+ <div class="wf-node-subtitle">{{ opLabel }}</div>
73
+ </div>
74
+ </div>
75
+
76
+ <div class="wf-node-content">
77
+ <div class="wf-node-description">{{ data.description }}</div>
78
+ <div v-if="inputLabel" class="wf-node-preview">
79
+ <div class="wf-node-preview-label">输入列表</div>
80
+ <div class="wf-node-preview-value">{{ inputLabel }}</div>
81
+ </div>
82
+ <div v-else class="wf-node-empty">
83
+ <span class="wf-node-empty-text">选择输入列表变量</span>
84
+ </div>
85
+ </div>
86
+
87
+ <NodeHandle
88
+ :id="id"
89
+ type="target"
90
+ position="Left"
91
+ class-name="flow-node-handle-left"
92
+ :style="{ background: '#22d3ee', border: '2px solid #ffffff' }"
93
+ />
94
+ <NodeHandle
95
+ :id="id"
96
+ type="source"
97
+ position="Right"
98
+ :is-hovered="isHovered"
99
+ class-name="flow-node-handle-right"
100
+ :style="{ background: '#22d3ee', border: '2px solid #ffffff' }"
101
+ @connection-plus-click="onConnectionPlusClick"
102
+ />
103
+ </div>
104
+ </template>
105
+
106
+ <style scoped>
107
+ .list-operator-node {
108
+ --wf-accent: #22d3ee;
109
+ --wf-accent-hover: #0891b2;
110
+ }
111
+ </style>
@@ -0,0 +1,94 @@
1
+ <script setup>
2
+ import { ref } from 'vue';
3
+
4
+ import Icon from '../Icon.vue';
5
+ import NodeHandle from '../NodeHandle.vue';
6
+ import NodeHoverToolbar from '../NodeHoverToolbar.vue';
7
+
8
+ const props = defineProps({
9
+ id: String,
10
+ data: {
11
+ type: Object,
12
+ default: () => ({
13
+ label: '循环',
14
+ description: '循环执行节点',
15
+ config: {
16
+ maxIterations: 10,
17
+ condition: '',
18
+ },
19
+ }),
20
+ },
21
+ });
22
+
23
+ const emit = defineEmits(['duplicate', 'delete', 'connection-plus-click']);
24
+
25
+ const isHovered = ref(false);
26
+
27
+ const onMouseEnter = () => (isHovered.value = true);
28
+ const onMouseLeave = () => (isHovered.value = false);
29
+ const duplicateNode = () => emit('duplicate', props.id);
30
+ const deleteNode = () => emit('delete', props.id);
31
+ const onConnectionPlusClick = (event, nodeId, handleId) => {
32
+ emit('connection-plus-click', event, nodeId, handleId);
33
+ };
34
+ </script>
35
+
36
+ <template>
37
+ <div
38
+ class="wf-node loop-node"
39
+ @mouseenter="onMouseEnter"
40
+ @mouseleave="onMouseLeave"
41
+ >
42
+ <NodeHoverToolbar
43
+ v-if="isHovered"
44
+ node-type="loop"
45
+ @duplicate="duplicateNode"
46
+ @delete="deleteNode"
47
+ />
48
+
49
+ <div class="wf-node-header">
50
+ <div class="wf-node-icon">
51
+ <Icon name="loop" />
52
+ </div>
53
+ <div class="wf-node-info">
54
+ <div class="wf-node-title">{{ data.label }}</div>
55
+ <div class="wf-node-subtitle">循环执行</div>
56
+ </div>
57
+ </div>
58
+
59
+ <div class="wf-node-content">
60
+ <div class="wf-node-description">{{ data.description }}</div>
61
+ <div v-if="data.config?.maxIterations" class="wf-node-preview">
62
+ <div class="wf-node-preview-label">最大迭代次数</div>
63
+ <div class="wf-node-preview-value">{{ data.config.maxIterations }}</div>
64
+ </div>
65
+ <div v-else class="wf-node-empty">
66
+ <span class="wf-node-empty-text">配置循环规则</span>
67
+ </div>
68
+ </div>
69
+
70
+ <NodeHandle
71
+ :id="id"
72
+ type="target"
73
+ position="Left"
74
+ class-name="flow-node-handle-left"
75
+ :style="{ background: '#dc2626', border: '2px solid #ffffff' }"
76
+ />
77
+ <NodeHandle
78
+ :id="id"
79
+ type="source"
80
+ position="Right"
81
+ :is-hovered="isHovered"
82
+ class-name="flow-node-handle-right"
83
+ :style="{ background: '#dc2626', border: '2px solid #ffffff' }"
84
+ @connection-plus-click="onConnectionPlusClick"
85
+ />
86
+ </div>
87
+ </template>
88
+
89
+ <style scoped>
90
+ .loop-node {
91
+ --wf-accent: #dc2626;
92
+ --wf-accent-hover: #b91c1c;
93
+ }
94
+ </style>