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,394 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * 工具 block. Shows a summary row (count + attached chips) and a `+ 添加` action.
4
+ * When adding, opens a Dify-style popover with a search input, category tabs,
5
+ * and a scrollable list — this mirrors Snipaste_2026-07-09_09-02-38.
6
+ *
7
+ * Both the attached-tools array and the full tool inventory come from the host.
8
+ */
9
+ import { computed, ref } from 'vue';
10
+
11
+ import type { StudioTool } from '../types';
12
+
13
+ interface Props {
14
+ attached: string[];
15
+ available: StudioTool[];
16
+ maxAttached?: number;
17
+ }
18
+
19
+ const props = withDefaults(defineProps<Props>(), {
20
+ maxAttached: 20,
21
+ });
22
+
23
+ const emit = defineEmits<{
24
+ (e: 'update:attached', v: string[]): void;
25
+ }>();
26
+
27
+ const showPicker = ref(false);
28
+ const search = ref('');
29
+ const activeCategory = ref('全部');
30
+
31
+ const CATEGORY_TABS = ['全部', '插件', '自定义', '工作流', 'MCP'];
32
+
33
+ const filtered = computed(() => {
34
+ const q = search.value.trim().toLowerCase();
35
+ return props.available.filter((t) => {
36
+ if (
37
+ activeCategory.value !== '全部' &&
38
+ (t.category ?? '插件') !== activeCategory.value
39
+ ) {
40
+ return false;
41
+ }
42
+ if (!q) return true;
43
+ return (
44
+ t.name.toLowerCase().includes(q) ||
45
+ (t.description ?? '').toLowerCase().includes(q)
46
+ );
47
+ });
48
+ });
49
+
50
+ const featured = computed(() =>
51
+ props.available
52
+ .slice()
53
+ .sort((a, b) => (b.installs ?? 0) - (a.installs ?? 0))
54
+ .slice(0, 5),
55
+ );
56
+
57
+ function isAttached(name: string) {
58
+ return props.attached.includes(name);
59
+ }
60
+
61
+ function toggle(name: string) {
62
+ const next = isAttached(name)
63
+ ? props.attached.filter((n) => n !== name)
64
+ : [...props.attached, name];
65
+ emit('update:attached', next);
66
+ }
67
+
68
+ function remove(name: string) {
69
+ emit(
70
+ 'update:attached',
71
+ props.attached.filter((n) => n !== name),
72
+ );
73
+ }
74
+ </script>
75
+
76
+ <template>
77
+ <div class="tool-card">
78
+ <div class="tool-head">
79
+ <div class="tool-title">
80
+ 工具
81
+ <span class="tool-help" title="工具能让智能体调用 API、检索、代码运行">
82
+
83
+ </span>
84
+ </div>
85
+ <div class="tool-head-right">
86
+ <span class="tool-count">{{ attached.length }}/{{ maxAttached }} 已挂载</span>
87
+ <button type="button" class="tool-add" @click="showPicker = !showPicker">
88
+ + 添加
89
+ </button>
90
+ </div>
91
+ </div>
92
+
93
+ <div v-if="attached.length === 0" class="tool-empty">
94
+ 还没挂载工具。点右上角"+ 添加"从工具箱选一个。
95
+ </div>
96
+ <div v-else class="tool-chip-row">
97
+ <span
98
+ v-for="name in attached"
99
+ :key="name"
100
+ class="tool-chip"
101
+ >
102
+ <span>🔧 {{ name }}</span>
103
+ <button
104
+ type="button"
105
+ class="tool-chip-x"
106
+ @click="remove(name)"
107
+ title="移除"
108
+ >
109
+ ×
110
+ </button>
111
+ </span>
112
+ </div>
113
+
114
+ <!-- Popover picker -->
115
+ <div v-if="showPicker" class="tool-pop">
116
+ <div class="tool-pop-head">
117
+ <input
118
+ v-model="search"
119
+ class="tool-search"
120
+ placeholder="搜索工具..."
121
+ />
122
+ <button
123
+ type="button"
124
+ class="tool-pop-close"
125
+ @click="showPicker = false"
126
+ >
127
+ ×
128
+ </button>
129
+ </div>
130
+ <div class="tool-pop-tabs">
131
+ <button
132
+ v-for="c in CATEGORY_TABS"
133
+ :key="c"
134
+ type="button"
135
+ class="tool-pop-tab"
136
+ :class="{ 'tool-pop-tab-active': activeCategory === c }"
137
+ @click="activeCategory = c"
138
+ >
139
+ {{ c }}
140
+ </button>
141
+ </div>
142
+ <div v-if="featured.length > 0 && !search" class="tool-pop-section">
143
+ <div class="tool-pop-section-title">精选推荐</div>
144
+ <div class="tool-pop-list">
145
+ <button
146
+ v-for="t in featured"
147
+ :key="`f-${t.name}`"
148
+ type="button"
149
+ class="tool-pop-item"
150
+ :class="{ 'tool-pop-item-active': isAttached(t.name) }"
151
+ @click="toggle(t.name)"
152
+ >
153
+ <span class="tool-pop-item-icon">{{ t.icon ?? '🔧' }}</span>
154
+ <span class="tool-pop-item-name">{{ t.name }}</span>
155
+ <span v-if="t.installs" class="tool-pop-item-installs">
156
+ {{ (t.installs / 1000).toFixed(0) }}k 次安装
157
+ </span>
158
+ </button>
159
+ </div>
160
+ </div>
161
+ <div class="tool-pop-section">
162
+ <div class="tool-pop-section-title">全部工具</div>
163
+ <div class="tool-pop-list">
164
+ <button
165
+ v-for="t in filtered"
166
+ :key="t.name"
167
+ type="button"
168
+ class="tool-pop-item"
169
+ :class="{ 'tool-pop-item-active': isAttached(t.name) }"
170
+ @click="toggle(t.name)"
171
+ >
172
+ <span class="tool-pop-item-icon">{{ t.icon ?? '🔧' }}</span>
173
+ <span class="tool-pop-item-name">{{ t.name }}</span>
174
+ <span class="tool-pop-item-desc">{{ t.description }}</span>
175
+ </button>
176
+ <div v-if="filtered.length === 0" class="tool-pop-empty">
177
+ 没有匹配的工具
178
+ </div>
179
+ </div>
180
+ </div>
181
+ </div>
182
+ </div>
183
+ </template>
184
+
185
+ <style scoped>
186
+ .tool-card {
187
+ position: relative;
188
+ padding: 12px 14px;
189
+ background: #fff;
190
+ border: 1px solid #e5e7eb;
191
+ border-radius: 12px;
192
+ }
193
+ .tool-head {
194
+ display: flex;
195
+ align-items: center;
196
+ justify-content: space-between;
197
+ }
198
+ .tool-title {
199
+ font-size: 13px;
200
+ font-weight: 600;
201
+ color: #334155;
202
+ }
203
+ .tool-help {
204
+ margin-left: 4px;
205
+ color: #94a3b8;
206
+ font-size: 11px;
207
+ cursor: help;
208
+ }
209
+ .tool-head-right {
210
+ display: flex;
211
+ align-items: center;
212
+ gap: 8px;
213
+ }
214
+ .tool-count {
215
+ font-size: 11px;
216
+ color: #94a3b8;
217
+ }
218
+ .tool-add {
219
+ padding: 2px 8px;
220
+ border: none;
221
+ border-radius: 6px;
222
+ background: transparent;
223
+ font-size: 12px;
224
+ color: #4338ca;
225
+ cursor: pointer;
226
+ }
227
+ .tool-add:hover {
228
+ background: #eef2ff;
229
+ }
230
+ .tool-empty {
231
+ margin-top: 8px;
232
+ font-size: 12px;
233
+ color: #94a3b8;
234
+ }
235
+ .tool-chip-row {
236
+ margin-top: 8px;
237
+ display: flex;
238
+ flex-wrap: wrap;
239
+ gap: 6px;
240
+ }
241
+ .tool-chip {
242
+ display: inline-flex;
243
+ align-items: center;
244
+ gap: 4px;
245
+ padding: 3px 6px 3px 10px;
246
+ background: #eef2ff;
247
+ color: #4338ca;
248
+ border-radius: 999px;
249
+ font-size: 12px;
250
+ }
251
+ .tool-chip-x {
252
+ padding: 0 4px;
253
+ border: none;
254
+ background: transparent;
255
+ color: inherit;
256
+ font-size: 14px;
257
+ cursor: pointer;
258
+ opacity: 0.7;
259
+ }
260
+ .tool-chip-x:hover {
261
+ opacity: 1;
262
+ }
263
+
264
+ /* Popover */
265
+ .tool-pop {
266
+ position: absolute;
267
+ top: 44px;
268
+ right: 12px;
269
+ width: 380px;
270
+ max-height: 440px;
271
+ overflow: hidden;
272
+ padding: 10px;
273
+ background: #fff;
274
+ border: 1px solid #e2e8f0;
275
+ border-radius: 12px;
276
+ box-shadow: 0 20px 40px rgba(15, 23, 42, 0.15);
277
+ z-index: 10;
278
+ display: flex;
279
+ flex-direction: column;
280
+ gap: 8px;
281
+ }
282
+ .tool-pop-head {
283
+ display: flex;
284
+ gap: 6px;
285
+ align-items: center;
286
+ }
287
+ .tool-search {
288
+ flex: 1;
289
+ padding: 6px 10px;
290
+ border: 1px solid #e2e8f0;
291
+ border-radius: 8px;
292
+ font-size: 12px;
293
+ outline: none;
294
+ }
295
+ .tool-search:focus {
296
+ border-color: #6366f1;
297
+ }
298
+ .tool-pop-close {
299
+ width: 26px;
300
+ height: 26px;
301
+ border: none;
302
+ background: transparent;
303
+ border-radius: 6px;
304
+ color: #94a3b8;
305
+ font-size: 16px;
306
+ cursor: pointer;
307
+ }
308
+ .tool-pop-close:hover {
309
+ background: #f1f5f9;
310
+ }
311
+ .tool-pop-tabs {
312
+ display: flex;
313
+ gap: 2px;
314
+ border-bottom: 1px solid #f1f5f9;
315
+ }
316
+ .tool-pop-tab {
317
+ padding: 4px 8px;
318
+ border: none;
319
+ background: transparent;
320
+ border-bottom: 2px solid transparent;
321
+ font-size: 12px;
322
+ color: #64748b;
323
+ cursor: pointer;
324
+ }
325
+ .tool-pop-tab-active {
326
+ color: #4338ca;
327
+ border-bottom-color: #4338ca;
328
+ }
329
+ .tool-pop-section-title {
330
+ padding: 6px 4px;
331
+ font-size: 11px;
332
+ font-weight: 600;
333
+ color: #94a3b8;
334
+ }
335
+ .tool-pop-list {
336
+ display: flex;
337
+ flex-direction: column;
338
+ gap: 2px;
339
+ max-height: 240px;
340
+ overflow-y: auto;
341
+ }
342
+ .tool-pop-item {
343
+ display: flex;
344
+ align-items: center;
345
+ gap: 8px;
346
+ padding: 6px 8px;
347
+ border: none;
348
+ background: transparent;
349
+ border-radius: 6px;
350
+ font-size: 12px;
351
+ text-align: left;
352
+ cursor: pointer;
353
+ }
354
+ .tool-pop-item:hover {
355
+ background: #f1f5f9;
356
+ }
357
+ .tool-pop-item-active {
358
+ background: #eef2ff;
359
+ }
360
+ .tool-pop-item-active::after {
361
+ content: '✓';
362
+ margin-left: auto;
363
+ color: #4338ca;
364
+ }
365
+ .tool-pop-item-icon {
366
+ flex-shrink: 0;
367
+ width: 20px;
368
+ text-align: center;
369
+ }
370
+ .tool-pop-item-name {
371
+ color: #0f172a;
372
+ font-weight: 500;
373
+ }
374
+ .tool-pop-item-desc {
375
+ margin-left: auto;
376
+ flex: 1;
377
+ color: #94a3b8;
378
+ overflow: hidden;
379
+ text-overflow: ellipsis;
380
+ white-space: nowrap;
381
+ max-width: 180px;
382
+ }
383
+ .tool-pop-item-installs {
384
+ margin-left: auto;
385
+ color: #94a3b8;
386
+ font-size: 11px;
387
+ }
388
+ .tool-pop-empty {
389
+ padding: 12px;
390
+ text-align: center;
391
+ color: #94a3b8;
392
+ font-size: 12px;
393
+ }
394
+ </style>
@@ -0,0 +1,205 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * 变量 block from Dify's orchestrate tab. Emits `add` and mutates rows in
4
+ * place — the host owns the array (v-model:list).
5
+ */
6
+ import type { PromptVariable, VariableType } from '../types';
7
+
8
+ interface Props {
9
+ list: PromptVariable[];
10
+ }
11
+
12
+ defineProps<Props>();
13
+
14
+ const emit = defineEmits<{
15
+ (e: 'update:list', v: PromptVariable[]): void;
16
+ }>();
17
+
18
+ const TYPE_OPTIONS: Array<{ label: string; value: VariableType }> = [
19
+ { label: '文本', value: 'text' },
20
+ { label: '段落', value: 'paragraph' },
21
+ { label: '下拉', value: 'select' },
22
+ ];
23
+
24
+ // Kept in script so the template's mustache parser doesn't try to eat the
25
+ // inner `{{` of the sample token.
26
+ const SAMPLE_TOKEN = '{' + '{#key#}' + '}';
27
+
28
+ function addRow(rows: PromptVariable[]) {
29
+ emit('update:list', [
30
+ ...rows,
31
+ { key: '', label: '', type: 'text', required: false },
32
+ ]);
33
+ }
34
+
35
+ function updateRow(rows: PromptVariable[], idx: number, patch: Partial<PromptVariable>) {
36
+ const next = rows.slice();
37
+ next[idx] = { ...next[idx]!, ...patch };
38
+ emit('update:list', next);
39
+ }
40
+
41
+ function removeRow(rows: PromptVariable[], idx: number) {
42
+ emit(
43
+ 'update:list',
44
+ rows.filter((_, i) => i !== idx),
45
+ );
46
+ }
47
+ </script>
48
+
49
+ <template>
50
+ <div class="var-card">
51
+ <div class="var-head">
52
+ <div class="var-title">
53
+ 变量
54
+ <span class="var-help" title="变量能让用户在表单里传入提示词,把它们插入到提示词中输入">
55
+
56
+ </span>
57
+ </div>
58
+ <button type="button" class="var-add" @click="addRow(list)">+ 添加</button>
59
+ </div>
60
+ <div v-if="list.length === 0" class="var-empty">
61
+ 变量能让用户在表单中输入提示词或直接引用。你可以试试在提示词中输入
62
+ <code>{{ SAMPLE_TOKEN }}</code>。
63
+ </div>
64
+ <div v-else class="var-list">
65
+ <div v-for="(row, i) in list" :key="i" class="var-row">
66
+ <input
67
+ class="var-input var-input-key"
68
+ :value="row.key"
69
+ placeholder="key"
70
+ @input="(e) => updateRow(list, i, { key: (e.target as HTMLInputElement).value })"
71
+ />
72
+ <input
73
+ class="var-input"
74
+ :value="row.label"
75
+ placeholder="展示名"
76
+ @input="(e) => updateRow(list, i, { label: (e.target as HTMLInputElement).value })"
77
+ />
78
+ <select
79
+ class="var-input var-input-type"
80
+ :value="row.type"
81
+ @change="(e) => updateRow(list, i, { type: (e.target as HTMLSelectElement).value as VariableType })"
82
+ >
83
+ <option v-for="o in TYPE_OPTIONS" :key="o.value" :value="o.value">
84
+ {{ o.label }}
85
+ </option>
86
+ </select>
87
+ <label class="var-required">
88
+ <input
89
+ type="checkbox"
90
+ :checked="row.required ?? false"
91
+ @change="(e) => updateRow(list, i, { required: (e.target as HTMLInputElement).checked })"
92
+ />
93
+ 必填
94
+ </label>
95
+ <button type="button" class="var-remove" @click="removeRow(list, i)">
96
+ ×
97
+ </button>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </template>
102
+
103
+ <style scoped>
104
+ .var-card {
105
+ padding: 12px 14px;
106
+ background: #fff;
107
+ border: 1px solid #e5e7eb;
108
+ border-radius: 12px;
109
+ }
110
+ .var-head {
111
+ display: flex;
112
+ align-items: center;
113
+ justify-content: space-between;
114
+ margin-bottom: 6px;
115
+ }
116
+ .var-title {
117
+ font-size: 13px;
118
+ font-weight: 600;
119
+ color: #334155;
120
+ }
121
+ .var-help {
122
+ margin-left: 4px;
123
+ color: #94a3b8;
124
+ font-size: 11px;
125
+ cursor: help;
126
+ }
127
+ .var-add {
128
+ padding: 2px 8px;
129
+ border: none;
130
+ border-radius: 6px;
131
+ background: transparent;
132
+ font-size: 12px;
133
+ color: #4338ca;
134
+ cursor: pointer;
135
+ }
136
+ .var-add:hover {
137
+ background: #eef2ff;
138
+ }
139
+ .var-empty {
140
+ padding: 4px 0;
141
+ font-size: 12px;
142
+ color: #94a3b8;
143
+ line-height: 1.5;
144
+ }
145
+ .var-empty code {
146
+ padding: 1px 5px;
147
+ background: #f1f5f9;
148
+ border-radius: 4px;
149
+ font-family: ui-monospace, monospace;
150
+ }
151
+ .var-list {
152
+ display: flex;
153
+ flex-direction: column;
154
+ gap: 6px;
155
+ }
156
+ .var-row {
157
+ display: flex;
158
+ gap: 6px;
159
+ align-items: center;
160
+ }
161
+ .var-input {
162
+ flex: 1;
163
+ min-width: 0;
164
+ padding: 5px 8px;
165
+ border: 1px solid #e2e8f0;
166
+ border-radius: 6px;
167
+ font-size: 12px;
168
+ background: #fff;
169
+ color: #0f172a;
170
+ }
171
+ .var-input:focus {
172
+ outline: none;
173
+ border-color: #6366f1;
174
+ box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.15);
175
+ }
176
+ .var-input-key {
177
+ flex: 0 0 100px;
178
+ font-family: ui-monospace, monospace;
179
+ }
180
+ .var-input-type {
181
+ flex: 0 0 72px;
182
+ }
183
+ .var-required {
184
+ display: inline-flex;
185
+ align-items: center;
186
+ gap: 4px;
187
+ font-size: 11px;
188
+ color: #64748b;
189
+ white-space: nowrap;
190
+ }
191
+ .var-remove {
192
+ padding: 0 6px;
193
+ height: 26px;
194
+ border: none;
195
+ border-radius: 6px;
196
+ background: transparent;
197
+ color: #94a3b8;
198
+ font-size: 16px;
199
+ cursor: pointer;
200
+ }
201
+ .var-remove:hover {
202
+ background: #fef2f2;
203
+ color: #dc2626;
204
+ }
205
+ </style>