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,347 @@
1
+ /**
2
+ * Small fetch-based client — mirrors the pattern in knowledge-hub / provider-hub.
3
+ */
4
+ import type { AgentEntity, AppTypeDescriptor, CreateAgentRequest } from '../types';
5
+
6
+ // `/agent-start` 是 spring-agent-web 给每个控制器加的固定命名空间前缀,属于
7
+ // 组件与后端约定的实现细节,宿主不用关心 —— 组件内部自己拼上就行。宿主
8
+ // 只需要告诉我们它转发到后端的代理前缀(默认 `/api`)。若代理不叫 /api,
9
+ // 传自定义 apiBase 或调 setAgentStudioApiBase() 覆盖。
10
+ const AGENT_START_NAMESPACE = '/agent-start';
11
+ let apiBase = '/api';
12
+
13
+ /**
14
+ * 追加到每个请求的 header。传函数会在每次请求前重新求值,方便宿主接入
15
+ * pinia store 里的 access-token —— 登录/退出时不用重挂 composable。
16
+ */
17
+ export type HeadersLike =
18
+ | Record<string, string>
19
+ | (() => Promise<Record<string, string>> | Record<string, string>);
20
+
21
+ let headersProvider: () => Promise<Record<string, string>> | Record<string, string> = () => ({});
22
+
23
+ export function setAgentStudioApiBase(base: string) {
24
+ apiBase = base.replace(/\/+$/, '');
25
+ }
26
+
27
+ /**
28
+ * 设置每次请求都会拼上的 header(如 Authorization)。示例:
29
+ * setAgentStudioHeaders(() => ({
30
+ * Authorization: `Bearer ${useAccessStore().accessToken}`,
31
+ * }));
32
+ * 传静态对象也可以 —— 但推荐用函数,避免 token 轮换后拿旧值。
33
+ */
34
+ export function setAgentStudioHeaders(headers: HeadersLike) {
35
+ headersProvider = typeof headers === 'function' ? headers : () => headers;
36
+ }
37
+
38
+ function buildUrl(path: string): string {
39
+ return `${apiBase}${AGENT_START_NAMESPACE}${path.startsWith('/') ? '' : '/'}${path}`;
40
+ }
41
+
42
+ async function resolveHeaders(): Promise<Record<string, string>> {
43
+ return (await headersProvider()) ?? {};
44
+ }
45
+
46
+ interface Envelope<T> {
47
+ code: string;
48
+ message?: string;
49
+ data: T;
50
+ }
51
+
52
+ async function call<T>(path: string, init: RequestInit = {}): Promise<T> {
53
+ const injected = await resolveHeaders();
54
+ const res = await fetch(buildUrl(path), {
55
+ headers: {
56
+ 'Content-Type': 'application/json',
57
+ ...injected,
58
+ ...(init.headers ?? {}),
59
+ },
60
+ ...init,
61
+ });
62
+ if (!res.ok) {
63
+ throw new Error(`${res.status} ${res.statusText}`);
64
+ }
65
+ const env = (await res.json()) as Envelope<T>;
66
+ if (env.code !== 'ok') {
67
+ throw new Error(env.message ?? env.code);
68
+ }
69
+ return env.data;
70
+ }
71
+
72
+ export function useAgentStudio() {
73
+ return {
74
+ listAgents: (tenantId?: string) =>
75
+ call<AgentEntity[]>(
76
+ `/agents${tenantId ? `?tenantId=${encodeURIComponent(tenantId)}` : ''}`,
77
+ ),
78
+ getAgent: (id: string) => call<AgentEntity>(`/agents/${id}`),
79
+ createAgent: (req: CreateAgentRequest) =>
80
+ call<AgentEntity>('/agents', {
81
+ method: 'POST',
82
+ body: JSON.stringify(req),
83
+ }),
84
+ updateAgent: (id: string, req: CreateAgentRequest) =>
85
+ call<AgentEntity>(`/agents/${id}`, {
86
+ method: 'PUT',
87
+ body: JSON.stringify(req),
88
+ }),
89
+ deleteAgent: (id: string) =>
90
+ call<void>(`/agents/${id}`, { method: 'DELETE' }),
91
+ };
92
+ }
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // Dify-style app-type descriptors.
96
+ //
97
+ // LEFT PANE (the tiles): small icon + title + short description — 84px tall.
98
+ // RIGHT PANE (the preview): a mocked, screenshot-style illustration of what
99
+ // the app looks like once created. We render these as inline SVGs (no image
100
+ // assets so the package stays dependency-free) — they're detailed enough to
101
+ // convey the visual character of each app type.
102
+ // ---------------------------------------------------------------------------
103
+
104
+ // Chatbot — a friendly two-bubble chat mock.
105
+ const CHATBOT_SVG = `
106
+ <svg viewBox="0 0 480 300" xmlns="http://www.w3.org/2000/svg">
107
+ <defs>
108
+ <linearGradient id="chatBg" x1="0" x2="0" y1="0" y2="1">
109
+ <stop offset="0" stop-color="#EEF4FF"/>
110
+ <stop offset="1" stop-color="#DBEAFE"/>
111
+ </linearGradient>
112
+ </defs>
113
+ <rect x="0" y="0" width="480" height="300" fill="url(#chatBg)"/>
114
+ <rect x="30" y="24" width="420" height="42" rx="10" fill="#fff" stroke="#e2e8f0"/>
115
+ <circle cx="52" cy="45" r="12" fill="#6366f1"/>
116
+ <text x="70" y="49" font-size="13" font-family="ui-sans-serif" fill="#111">对话应用</text>
117
+ <text x="70" y="62" font-size="10" font-family="ui-sans-serif" fill="#94a3b8">在线</text>
118
+ <!-- Bot bubble -->
119
+ <rect x="30" y="86" width="220" height="52" rx="14" fill="#fff" stroke="#e0e7ff"/>
120
+ <text x="46" y="108" font-size="12" fill="#334155">👋 你好,我可以帮你什么?</text>
121
+ <text x="46" y="126" font-size="10" fill="#94a3b8">刚刚</text>
122
+ <!-- User bubble -->
123
+ <rect x="230" y="152" width="220" height="52" rx="14" fill="#4f46e5"/>
124
+ <text x="246" y="174" font-size="12" fill="#eef2ff">帮我总结这个文档</text>
125
+ <text x="246" y="192" font-size="10" fill="#c7d2fe">刚刚 · 已读</text>
126
+ <!-- Bot bubble 2 -->
127
+ <rect x="30" y="220" width="280" height="52" rx="14" fill="#fff" stroke="#e0e7ff"/>
128
+ <text x="46" y="242" font-size="12" fill="#334155">好的,我先读一下...</text>
129
+ <circle cx="298" cy="246" r="3" fill="#94a3b8">
130
+ <animate attributeName="opacity" values="0.3;1;0.3" dur="1.2s" repeatCount="indefinite"/>
131
+ </circle>
132
+ </svg>`;
133
+
134
+ // Agent — a "brain + tool orbits" mock.
135
+ const AGENT_SVG = `
136
+ <svg viewBox="0 0 480 300" xmlns="http://www.w3.org/2000/svg">
137
+ <defs>
138
+ <linearGradient id="agentBg" x1="0" x2="0" y1="0" y2="1">
139
+ <stop offset="0" stop-color="#F0FDF4"/>
140
+ <stop offset="1" stop-color="#DCFCE7"/>
141
+ </linearGradient>
142
+ </defs>
143
+ <rect x="0" y="0" width="480" height="300" fill="url(#agentBg)"/>
144
+ <!-- center agent core -->
145
+ <circle cx="240" cy="150" r="52" fill="#fff" stroke="#86efac" stroke-width="2"/>
146
+ <circle cx="240" cy="150" r="42" fill="#dcfce7"/>
147
+ <text x="222" y="164" font-size="32">🤖</text>
148
+ <text x="215" y="220" font-size="11" fill="#065f46" font-weight="600">Agent 核心</text>
149
+ <!-- tool nodes with dashed lines -->
150
+ <g stroke="#059669" stroke-width="1.5" stroke-dasharray="4 3" fill="none">
151
+ <path d="M 200 120 Q 130 90 80 70"/>
152
+ <path d="M 200 180 Q 130 200 80 230"/>
153
+ <path d="M 280 120 Q 360 90 400 70"/>
154
+ <path d="M 280 180 Q 360 210 400 230"/>
155
+ </g>
156
+ <g font-family="ui-sans-serif">
157
+ <rect x="30" y="52" width="100" height="36" rx="8" fill="#fff" stroke="#86efac"/>
158
+ <text x="46" y="76" font-size="12" fill="#065f46">🔍 web_search</text>
159
+ <rect x="30" y="212" width="100" height="36" rx="8" fill="#fff" stroke="#86efac"/>
160
+ <text x="46" y="236" font-size="12" fill="#065f46">🧮 calculator</text>
161
+ <rect x="350" y="52" width="100" height="36" rx="8" fill="#fff" stroke="#86efac"/>
162
+ <text x="368" y="76" font-size="12" fill="#065f46">📚 knowledge</text>
163
+ <rect x="350" y="212" width="100" height="36" rx="8" fill="#fff" stroke="#86efac"/>
164
+ <text x="368" y="236" font-size="12" fill="#065f46">🌐 http_request</text>
165
+ </g>
166
+ </svg>`;
167
+
168
+ // Workflow — a small DAG.
169
+ const WORKFLOW_SVG = `
170
+ <svg viewBox="0 0 480 300" xmlns="http://www.w3.org/2000/svg">
171
+ <defs>
172
+ <linearGradient id="wfBg" x1="0" x2="0" y1="0" y2="1">
173
+ <stop offset="0" stop-color="#FEF6EE"/>
174
+ <stop offset="1" stop-color="#FED7AA"/>
175
+ </linearGradient>
176
+ </defs>
177
+ <rect x="0" y="0" width="480" height="300" fill="url(#wfBg)"/>
178
+ <!-- nodes -->
179
+ <g font-family="ui-sans-serif" font-size="11">
180
+ <rect x="30" y="130" width="76" height="40" rx="8" fill="#fff" stroke="#f97316"/>
181
+ <text x="52" y="155" fill="#7c2d12">▶ 开始</text>
182
+ <rect x="164" y="60" width="96" height="40" rx="8" fill="#fff" stroke="#f97316"/>
183
+ <text x="184" y="85" fill="#7c2d12">🧠 LLM 节点</text>
184
+ <rect x="164" y="200" width="96" height="40" rx="8" fill="#fff" stroke="#f97316"/>
185
+ <text x="180" y="225" fill="#7c2d12">📚 知识检索</text>
186
+ <rect x="318" y="130" width="96" height="40" rx="8" fill="#fff" stroke="#f97316"/>
187
+ <text x="336" y="155" fill="#7c2d12">🔀 IF / ELSE</text>
188
+ <rect x="452" y="115" width="0" height="0"/>
189
+ </g>
190
+ <!-- 结束 -->
191
+ <rect x="405" y="45" width="60" height="30" rx="6" fill="#fff" stroke="#f97316" stroke-dasharray="3 2"/>
192
+ <text x="418" y="65" font-size="10" fill="#7c2d12">✅ 完成</text>
193
+ <rect x="405" y="225" width="60" height="30" rx="6" fill="#fff" stroke="#f97316" stroke-dasharray="3 2"/>
194
+ <text x="418" y="245" font-size="10" fill="#7c2d12">❌ 失败</text>
195
+ <!-- edges -->
196
+ <g stroke="#c2410c" stroke-width="1.5" fill="none">
197
+ <path d="M 106 150 L 130 150 L 130 80 L 164 80"/>
198
+ <path d="M 106 150 L 130 150 L 130 220 L 164 220"/>
199
+ <path d="M 260 80 L 285 80 L 285 145 L 318 145"/>
200
+ <path d="M 260 220 L 285 220 L 285 155 L 318 155"/>
201
+ <path d="M 414 130 L 425 90 L 425 75"/>
202
+ <path d="M 414 170 L 425 210 L 425 225"/>
203
+ </g>
204
+ </svg>`;
205
+
206
+ // Chatflow — a compact DAG (START → LLM → 直接回复) next to a chat preview
207
+ // panel. Mirrors Dify's chatflow tile: same visual canvas as workflow, but the
208
+ // terminal node is a "直接回复 (ANSWER)" instead of a generic 结束, and there
209
+ // is a chat bubble panel on the right showing the streamed answer.
210
+ const CHATFLOW_SVG = `
211
+ <svg viewBox="0 0 480 300" xmlns="http://www.w3.org/2000/svg">
212
+ <defs>
213
+ <linearGradient id="cfBg" x1="0" x2="0" y1="0" y2="1">
214
+ <stop offset="0" stop-color="#EEF4FF"/>
215
+ <stop offset="1" stop-color="#E0E7FF"/>
216
+ </linearGradient>
217
+ </defs>
218
+ <rect x="0" y="0" width="480" height="300" fill="url(#cfBg)"/>
219
+ <!-- LEFT: mini DAG -->
220
+ <g font-family="ui-sans-serif" font-size="10">
221
+ <rect x="20" y="60" width="72" height="34" rx="8" fill="#fff" stroke="#6366f1"/>
222
+ <text x="34" y="82" fill="#3730a3">▶ 开始</text>
223
+ <rect x="110" y="60" width="72" height="34" rx="8" fill="#fff" stroke="#6366f1"/>
224
+ <text x="124" y="82" fill="#3730a3">🧠 LLM</text>
225
+ <rect x="200" y="60" width="88" height="34" rx="8" fill="#fff" stroke="#4f46e5" stroke-width="1.5"/>
226
+ <text x="212" y="82" fill="#3730a3">💬 直接回复</text>
227
+ <g stroke="#818cf8" stroke-width="1.5" fill="none">
228
+ <path d="M 92 77 L 110 77"/>
229
+ <path d="M 182 77 L 200 77"/>
230
+ </g>
231
+ <!-- 记忆挂饰 -->
232
+ <rect x="20" y="120" width="120" height="26" rx="6" fill="#fff" stroke="#c7d2fe" stroke-dasharray="3 2"/>
233
+ <text x="32" y="138" fill="#4338ca">🧠 对话记忆 · 20 轮</text>
234
+ <rect x="150" y="120" width="138" height="26" rx="6" fill="#fff" stroke="#c7d2fe" stroke-dasharray="3 2"/>
235
+ <text x="162" y="138" fill="#4338ca">🌊 SSE 流式输出</text>
236
+ </g>
237
+ <!-- Divider -->
238
+ <line x1="300" y1="20" x2="300" y2="280" stroke="#c7d2fe" stroke-dasharray="4 4"/>
239
+ <!-- RIGHT: chat preview panel -->
240
+ <g font-family="ui-sans-serif">
241
+ <rect x="316" y="24" width="140" height="18" rx="4" fill="#4f46e5"/>
242
+ <text x="326" y="37" font-size="10" fill="#eef2ff">Chatflow 预览</text>
243
+ <!-- user bubble -->
244
+ <rect x="336" y="56" width="120" height="34" rx="10" fill="#4f46e5"/>
245
+ <text x="346" y="76" font-size="10" fill="#eef2ff">波士顿今天天气?</text>
246
+ <!-- assistant bubble -->
247
+ <rect x="316" y="102" width="140" height="60" rx="10" fill="#fff" stroke="#c7d2fe"/>
248
+ <text x="326" y="120" font-size="10" fill="#334155">今日多云,最高 22°C</text>
249
+ <text x="326" y="134" font-size="10" fill="#334155">最低 15°C。傍晚可能</text>
250
+ <text x="326" y="148" font-size="10" fill="#334155">有阵雨,注意携带雨具。</text>
251
+ <!-- streaming caret -->
252
+ <rect x="326" y="170" width="4" height="10" fill="#4f46e5">
253
+ <animate attributeName="opacity" values="0.2;1;0.2" dur="1s" repeatCount="indefinite"/>
254
+ </rect>
255
+ <text x="336" y="180" font-size="9" fill="#94a3b8">流式输出中…</text>
256
+ <!-- input row -->
257
+ <rect x="316" y="240" width="112" height="26" rx="13" fill="#fff" stroke="#c7d2fe"/>
258
+ <text x="326" y="257" font-size="10" fill="#94a3b8">和 Bot 聊天…</text>
259
+ <circle cx="446" cy="253" r="10" fill="#4f46e5"/>
260
+ <text x="442" y="257" font-size="10" fill="#fff">➤</text>
261
+ </g>
262
+ </svg>`;
263
+
264
+ // Text generator — form input + generated block.
265
+ const TEXT_GEN_SVG = `
266
+ <svg viewBox="0 0 480 300" xmlns="http://www.w3.org/2000/svg">
267
+ <defs>
268
+ <linearGradient id="tgBg" x1="0" x2="0" y1="0" y2="1">
269
+ <stop offset="0" stop-color="#FEF2F2"/>
270
+ <stop offset="1" stop-color="#FEE2E2"/>
271
+ </linearGradient>
272
+ </defs>
273
+ <rect x="0" y="0" width="480" height="300" fill="url(#tgBg)"/>
274
+ <!-- Input form -->
275
+ <rect x="30" y="26" width="420" height="20" rx="4" fill="#fff" stroke="#fca5a5"/>
276
+ <text x="40" y="41" font-size="11" fill="#94a3b8">主题:</text>
277
+ <text x="85" y="41" font-size="11" fill="#1e293b">Q3 产品复盘要点</text>
278
+ <rect x="30" y="54" width="200" height="20" rx="4" fill="#fff" stroke="#fca5a5"/>
279
+ <text x="40" y="69" font-size="11" fill="#94a3b8">语调:</text>
280
+ <text x="85" y="69" font-size="11" fill="#1e293b">正式</text>
281
+ <rect x="250" y="54" width="200" height="20" rx="4" fill="#fff" stroke="#fca5a5"/>
282
+ <text x="260" y="69" font-size="11" fill="#94a3b8">长度:</text>
283
+ <text x="305" y="69" font-size="11" fill="#1e293b">300 字</text>
284
+ <rect x="380" y="88" width="70" height="24" rx="4" fill="#dc2626"/>
285
+ <text x="398" y="105" font-size="12" fill="#fff">▶ 生成</text>
286
+ <!-- Divider line -->
287
+ <line x1="30" y1="128" x2="450" y2="128" stroke="#fca5a5" stroke-dasharray="3 3"/>
288
+ <text x="30" y="145" font-size="11" fill="#94a3b8">生成结果</text>
289
+ <!-- Output block -->
290
+ <rect x="30" y="152" width="420" height="130" rx="8" fill="#fff" stroke="#fca5a5"/>
291
+ <text x="45" y="174" font-size="12" fill="#1e293b" font-weight="600">Q3 产品复盘:三大关键洞察</text>
292
+ <text x="45" y="196" font-size="11" fill="#475569">1. 新用户留存率环比提升 12%,与 v2.1</text>
293
+ <text x="45" y="212" font-size="11" fill="#475569"> 的 onboarding 改动强相关;</text>
294
+ <text x="45" y="230" font-size="11" fill="#475569">2. 高付费用户 ARPU 略微下降,需重点</text>
295
+ <text x="45" y="246" font-size="11" fill="#475569"> 排查 Enterprise 计划 SLA 问题;</text>
296
+ <text x="45" y="264" font-size="11" fill="#94a3b8">▍ 正在生成...</text>
297
+ </svg>`;
298
+
299
+ export const APP_TYPES: AppTypeDescriptor[] = [
300
+ {
301
+ id: 'chatbot',
302
+ title: '对话应用',
303
+ description: '轻量级 Chat:模型 + 记忆 + 系统 Prompt。',
304
+ hint: 'REACT 策略 · 保留 20 轮对话记忆',
305
+ icon: '💬',
306
+ iconBg: '#EEF4FF',
307
+ previewSvg: CHATBOT_SVG,
308
+ },
309
+ {
310
+ id: 'agent',
311
+ title: 'Agent 应用',
312
+ description: '让模型调用工具的推理循环,可自主搜索、计算、执行。',
313
+ hint: 'FUNCTION_CALLING · 可挂多工具 · 最多 6 轮',
314
+ icon: '🤖',
315
+ iconBg: '#EFFDF4',
316
+ previewSvg: AGENT_SVG,
317
+ },
318
+ {
319
+ id: 'workflow',
320
+ title: '工作流',
321
+ description: '面向单任务的可视化编排工作流。',
322
+ hint: '拖拽节点编排 · 一次性执行 · 无对话记忆',
323
+ icon: '🧬',
324
+ iconBg: '#FEF6EE',
325
+ previewSvg: WORKFLOW_SVG,
326
+ },
327
+ {
328
+ id: 'chatflow',
329
+ title: 'Chatflow',
330
+ description: '支持记忆的复杂多步骤对话工作流。',
331
+ hint: '拖拽节点编排 · 保留对话记忆 · 支持流式输出',
332
+ icon: '💠',
333
+ iconBg: '#EEF4FF',
334
+ // 与 workflow 共用画布,但收尾是"直接回复 (ANSWER)" 节点,并附带对话记忆
335
+ // 与流式输出 —— 缩略图突出这套差异化,避免与 workflow 混为一谈。
336
+ previewSvg: CHATFLOW_SVG,
337
+ },
338
+ {
339
+ id: 'text-generator',
340
+ title: '文本生成应用',
341
+ description: '固定 Prompt + 参数化变量,一次调用生成长文本。',
342
+ hint: 'PLAN_EXECUTE · 单次输出 · 支持变量',
343
+ icon: '📝',
344
+ iconBg: '#FEF2F2',
345
+ previewSvg: TEXT_GEN_SVG,
346
+ },
347
+ ];
@@ -0,0 +1,60 @@
1
+ /**
2
+ * @agent-start/agent-studio
3
+ *
4
+ * Reusable agent-studio component + composable kit for spring-agent-start,
5
+ * modeled after Dify's application studio.
6
+ *
7
+ * ── Application list side ────────────────────────────────────────────────
8
+ * AgentCardGrid — Dify-style grid of agents with a leading "+新建" card
9
+ * + inline chat/edit/share/delete actions surfaced as events.
10
+ * CreateAppModal — 4-way picker with SVG preview per app type (chatbot /
11
+ * agent / workflow / text-generator). Emits `select` with
12
+ * the chosen type + a canonical default-config hint.
13
+ *
14
+ * ── Application editor side (mirrors Dify's 编辑页) ──────────────────────
15
+ * AgentStudioShell — left-nav shell (agent header + 编排/API/日志/监测)
16
+ * AgentOrchestrate — 编排 tab (提示词/变量/知识库/元数据过滤/工具/视觉)
17
+ * AgentPromptEditor — Prompt textarea + variable insertion popover
18
+ * AgentVariablesPanel — Variable rows (key / label / type / required)
19
+ * AgentToolsPanel — Tool list + Dify-style picker popover
20
+ * AgentDebugPanel — Right-side 调试与预览 chat pane
21
+ * AgentApiDocs — 访问 API tab (base URL + auth + endpoint list)
22
+ * AgentLogsPanel — 日志与标注 tab (filterable table + pagination)
23
+ * AgentMonitorPanel — 监测 tab (metric cards backed by SparkChart)
24
+ * SparkChart — Dependency-free SVG area/line chart
25
+ *
26
+ * useAgentStudio() — thin fetch client over /api/agent-start/agents.
27
+ * APP_TYPES — the picker cards' data (icon / svg / hint).
28
+ *
29
+ * Consumers alias it as `@agent-start/agent-studio` (see vite.config.mts).
30
+ */
31
+
32
+ // Application list side
33
+ export { default as AgentCardGrid } from './components/AgentCardGrid.vue';
34
+ export { default as AppDesignDrawer } from './components/AppDesignDrawer.vue';
35
+ export { default as CreateAppModal } from './components/CreateAppModal.vue';
36
+
37
+ // Application editor side — the Dify studio
38
+ export { default as AgentApiDocs } from './components/AgentApiDocs.vue';
39
+ export { default as ApiKeyManager } from './components/ApiKeyManager.vue';
40
+ export { default as AgentDebugPanel } from './components/AgentDebugPanel.vue';
41
+ export { default as AgentLogsPanel } from './components/AgentLogsPanel.vue';
42
+ export { default as AgentMonitorPanel } from './components/AgentMonitorPanel.vue';
43
+ export { default as AgentOrchestrate } from './components/AgentOrchestrate.vue';
44
+ export { default as AgentPromptEditor } from './components/AgentPromptEditor.vue';
45
+ export { default as AgentStudioShell } from './components/AgentStudioShell.vue';
46
+ export { default as AgentToolsPanel } from './components/AgentToolsPanel.vue';
47
+ export { default as AgentVariablesPanel } from './components/AgentVariablesPanel.vue';
48
+ export { default as SparkChart } from './components/SparkChart.vue';
49
+
50
+ export * from './composables/useAgentStudio';
51
+ export * from './types';
52
+
53
+ // Panels used by AppDesignDrawer's built-in tab content. Re-exported so a
54
+ // host that wants finer-grained composition (embed a single panel in its own
55
+ // page) can pull them individually. AppStudioApi is the callback bag every
56
+ // panel is wired against.
57
+ export { default as DrawerFlowDesigner } from './panels/DrawerFlowDesigner.vue';
58
+ export { default as LogAnnotationPanel } from './panels/LogAnnotationPanel.vue';
59
+ export { default as MonitorPanel } from './panels/MonitorPanel.vue';
60
+ export * from './api';
@@ -0,0 +1,203 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * Drawer-embedded FlowDesigner glue — used by {@code AppDesignDrawer} to slot
4
+ * a visual-workflow canvas into the "编排" tab for workflow / chatflow apps.
5
+ *
6
+ * Handles:
7
+ * • Register the {@code FlowDesigner} instance up to the drawer via the
8
+ * {@code registerDesigner} callback (drawer uses it for {@code getFlowInfo}
9
+ * / {@code reloadGraph} on save).
10
+ * • Watch {@code initialGraphJson} — the drawer often opens synchronously
11
+ * and only later awaits the saved draft; a one-shot mount hook would lock
12
+ * the canvas on the 3-node seed. Reloading on every meaningful change
13
+ * keeps the async load path correct.
14
+ * • Legacy graph shape upgrade — designer used to save lowercase
15
+ * kebab-case type names ({@code condition}, {@code user-input}); backend
16
+ * now standardises on UPPER_SNAKE (matching {@code NodeType}). The
17
+ * upgrade table maps the old names on load so existing saves still render.
18
+ * • Node config panel on the right — the standalone /agent-flow view has
19
+ * the same layout, we mirror it here.
20
+ */
21
+ import { computed, nextTick, onMounted, ref, shallowRef, watch } from 'vue';
22
+
23
+ import FlowDesigner from '../../agent-flow/workflow/FlowDesigner.vue';
24
+ import NodeConfigCard from '../../agent-flow/workflow/NodeConfigCard.vue';
25
+
26
+ interface Props {
27
+ initialGraphJson?: string;
28
+ registerDesigner: (inst: any) => void;
29
+ /**
30
+ * Owning app id — forwarded to {@code <FlowDesigner :app-id>} so the
31
+ * component's own top-bar 保存草稿 / 发布 buttons include it in their
32
+ * BackendAdapter payloads. Missing appId turns those buttons into no-ops
33
+ * with an inline error message rather than posting an orphaned row.
34
+ */
35
+ appId?: string;
36
+ /**
37
+ * Raw app mode ({@code 'workflow'} | {@code 'chatflow'} | others). Forwarded
38
+ * up to {@link FlowDesigner} as {@code mode="WORKFLOW"} / {@code "CHATFLOW"}
39
+ * so its {@code initGraph()} seeds the correct 3-node default — workflow
40
+ * ends with a plain 结束 (END), chatflow ends with 直接回复 (ANSWER).
41
+ * Missing / unknown mode defaults to {@code "WORKFLOW"}.
42
+ */
43
+ appMode?: string;
44
+ }
45
+ const props = defineProps<Props>();
46
+
47
+ const designerMode = computed(() => {
48
+ const m = (props.appMode ?? '').toLowerCase();
49
+ if (m === 'chatflow') return 'CHATFLOW';
50
+ return 'WORKFLOW';
51
+ });
52
+
53
+ const designerRef = shallowRef<any>(null);
54
+ const selectedNode = ref<any>(null);
55
+
56
+ function onNodeClick(node: any) {
57
+ selectedNode.value = node;
58
+ }
59
+ function onNodeDelete() {
60
+ selectedNode.value = null;
61
+ }
62
+ function onCloseConfig() {
63
+ selectedNode.value = null;
64
+ }
65
+ function onConfigDataChange({ nodeId, data }: { nodeId: string; data: any }) {
66
+ designerRef.value?.patchNodeData?.(nodeId, data);
67
+ }
68
+
69
+ /**
70
+ * Parse a raw graph JSON string into a VueFlow-ready object, or return
71
+ * {@code null} when the payload is empty / invalid / a legacy backend-format
72
+ * dump. FlowDesigner takes {@code null} as "fall back to your own initGraph()
73
+ * seed", so the caller doesn't have to handle the empty-canvas branch.
74
+ */
75
+ function parseGraph(json?: string): any {
76
+ if (!json) return null;
77
+ try {
78
+ const parsed = JSON.parse(json);
79
+ if (parsed?.nodes?.length && !isLegacyBackendGraph(parsed)) {
80
+ normalizeNodeTypes(parsed);
81
+ return parsed;
82
+ }
83
+ } catch {
84
+ // fall through
85
+ }
86
+ return null;
87
+ }
88
+
89
+ onMounted(async () => {
90
+ await nextTick();
91
+ if (!designerRef.value) return;
92
+ props.registerDesigner(designerRef.value);
93
+ designerRef.value.reloadGraph?.(parseGraph(props.initialGraphJson));
94
+ });
95
+
96
+ /**
97
+ * The drawer opens synchronously, then asynchronously fetches the saved
98
+ * draft and writes it into the prop. A one-shot mount hook would leave the
99
+ * canvas stuck on the 3-node seed ("save works but reload shows nothing").
100
+ * Watching the prop and re-invoking {@code reloadGraph} on every meaningful
101
+ * change closes that loop.
102
+ *
103
+ * <p>Only reload when the JSON actually resolves to a valid graph — an empty
104
+ * string flip while the fetch is in flight would otherwise wipe an
105
+ * already-loaded canvas back to the seed.</p>
106
+ */
107
+ watch(
108
+ () => props.initialGraphJson,
109
+ async (json, prev) => {
110
+ if (json === prev) return;
111
+ const graph = parseGraph(json);
112
+ if (graph == null) return;
113
+ await nextTick();
114
+ designerRef.value?.reloadGraph?.(graph);
115
+ },
116
+ );
117
+
118
+ /**
119
+ * The designer now saves node types as canonical backend {@code NodeType}
120
+ * names (UPPER_SNAKE) — same identifier VueFlow uses to pick a
121
+ * {@code #node-XXX} slot. Upgrade any pre-rename graph in place so opening
122
+ * a legacy row still hooks up the visual palette.
123
+ */
124
+ const LEGACY_TYPE_UPGRADE: Record<string, string> = {
125
+ CONDITION: 'IF_ELSE',
126
+ CLASSIFIER: 'QUESTION_CLASSIFIER',
127
+ HTTP: 'HTTP_REQUEST',
128
+ TEMPLATE: 'TEMPLATE_TRANSFORM',
129
+ VARIABLE: 'VARIABLE_AGGREGATOR',
130
+ };
131
+
132
+ function normalizeNodeTypes(g: any) {
133
+ if (!Array.isArray(g?.nodes)) return;
134
+ for (const n of g.nodes) {
135
+ if (typeof n?.type !== 'string') continue;
136
+ const upper = n.type.toUpperCase().replace(/-/g, '_');
137
+ n.type = LEGACY_TYPE_UPGRADE[upper] ?? upper;
138
+ }
139
+ }
140
+
141
+ /**
142
+ * Detect a *truly* legacy backend-format graph shape from earlier prototypes:
143
+ * nodes with canonical string ids like {@code "start"}/{@code "end"} and no
144
+ * {@code position} field. VueFlow can't render those; discard and fall back
145
+ * to the seed.
146
+ */
147
+ function isLegacyBackendGraph(g: any): boolean {
148
+ if (!Array.isArray(g?.nodes)) return false;
149
+ return g.nodes.some(
150
+ (n: any) => !n?.position || ['end', 'start'].includes(String(n?.id ?? '')),
151
+ );
152
+ }
153
+ </script>
154
+
155
+ <template>
156
+ <div class="drawer-flow-host">
157
+ <div class="drawer-flow-canvas">
158
+ <FlowDesigner
159
+ ref="designerRef"
160
+ :mode="designerMode"
161
+ :app-id="appId"
162
+ :embedded="true"
163
+ class="drawer-flow-fill"
164
+ @node-click="onNodeClick"
165
+ @node-delete="onNodeDelete"
166
+ />
167
+ </div>
168
+ <div v-if="selectedNode" class="drawer-flow-panel">
169
+ <NodeConfigCard
170
+ :select-node="selectedNode"
171
+ @on-close="onCloseConfig"
172
+ @data-change="onConfigDataChange"
173
+ />
174
+ </div>
175
+ </div>
176
+ </template>
177
+
178
+ <style scoped>
179
+ .drawer-flow-host {
180
+ position: relative;
181
+ display: flex;
182
+ width: 100%;
183
+ height: 100%;
184
+ min-height: 0;
185
+ }
186
+ .drawer-flow-canvas {
187
+ flex: 1;
188
+ min-width: 0;
189
+ min-height: 0;
190
+ height: 100%;
191
+ position: relative;
192
+ }
193
+ .drawer-flow-fill {
194
+ width: 100%;
195
+ height: 100%;
196
+ }
197
+ .drawer-flow-panel {
198
+ flex: none;
199
+ border-left: 1px solid #e5e7eb;
200
+ background: #fff;
201
+ min-height: 0;
202
+ }
203
+ </style>