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,515 @@
1
+ <script setup lang="ts">
2
+ /**
3
+ * RecallTestingPanelV2 — Dify-parity 召回测试 tab (screenshot 5).
4
+ *
5
+ * The 检索设置 lives in a floating {@link RetrievalConfigPopover} anchored to
6
+ * the top-right method button of the query textarea. Everything the popover
7
+ * carries (method + rerank + TopK + score threshold) round-trips through a
8
+ * single {@link RetrievalConfig} v-model, matching the shape the wizard and
9
+ * the settings panel already speak.
10
+ */
11
+ import { computed, ref } from 'vue';
12
+
13
+ import type { RecallHit, RecentQuery } from '../types';
14
+ import type {
15
+ IndexingTechnique,
16
+ RetrievalConfig,
17
+ } from '../types/dataset';
18
+ import RetrievalConfigPopover from './RetrievalConfigPopover.vue';
19
+
20
+ interface Props {
21
+ hits?: RecallHit[];
22
+ history?: RecentQuery[];
23
+ loading?: boolean;
24
+ /**
25
+ * Seed for the popover so the panel opens showing the dataset's current
26
+ * retrieval config, not defaults. Callers typically parse the dataset's
27
+ * {@code retrievalConfigJson} once and pass it in.
28
+ */
29
+ initialConfig?: RetrievalConfig;
30
+ rerankModels?: Array<{ id: string; label: string }>;
31
+ indexingTechnique?: IndexingTechnique;
32
+ }
33
+
34
+ const props = withDefaults(defineProps<Props>(), {
35
+ hits: () => [],
36
+ history: () => [],
37
+ loading: false,
38
+ initialConfig: () => ({ method: 'VECTOR', topK: 3 }),
39
+ rerankModels: () => [],
40
+ });
41
+
42
+ const emit = defineEmits<{
43
+ (
44
+ e: 'run',
45
+ payload: { query: string; method: string; config: RetrievalConfig },
46
+ ): void;
47
+ (e: 'replay', h: RecentQuery): void;
48
+ }>();
49
+
50
+ const query = ref('');
51
+ const config = ref<RetrievalConfig>({ ...props.initialConfig });
52
+
53
+ const methodLabel = computed(() => {
54
+ if (config.value.method === 'HYBRID') return '混合检索';
55
+ if (config.value.method === 'FULL_TEXT') return '全文检索';
56
+ return '向量检索';
57
+ });
58
+ const methodIcon = computed(() => {
59
+ if (config.value.method === 'HYBRID') return '⚡';
60
+ if (config.value.method === 'FULL_TEXT') return '≡';
61
+ return '◈';
62
+ });
63
+
64
+ const charCount = computed(() => query.value.length);
65
+ const canRun = computed(() => query.value.trim().length > 0);
66
+
67
+ // Popover trigger anchor + open state.
68
+ const methodBtnRef = ref<HTMLElement | null>(null);
69
+ const popoverOpen = ref(false);
70
+ function toggleConfig() {
71
+ popoverOpen.value = !popoverOpen.value;
72
+ }
73
+
74
+ function run() {
75
+ if (!canRun.value) return;
76
+ emit('run', {
77
+ query: query.value,
78
+ method: config.value.method ?? 'VECTOR',
79
+ config: { ...config.value },
80
+ });
81
+ }
82
+
83
+ function replay(h: RecentQuery) {
84
+ query.value = h.query;
85
+ emit('replay', h);
86
+ }
87
+ </script>
88
+
89
+ <template>
90
+ <div class="kh-recall">
91
+ <div class="kh-recall-header">
92
+ <div class="kh-recall-title">召回测试</div>
93
+ <div class="kh-recall-sub">根据给定的查询文本测试知识的召回效果。</div>
94
+ </div>
95
+
96
+ <div class="kh-recall-body">
97
+ <!-- LEFT -->
98
+ <div class="kh-recall-left">
99
+ <div class="kh-recall-input-wrap">
100
+ <div class="kh-recall-input-toolbar">
101
+ <span class="kh-recall-input-label">源文本</span>
102
+ <!-- 混合检索 icon button — opens the popover-style 检索设置 card.
103
+ The button is only the anchor; the card is Teleport'd to <body>
104
+ in RetrievalConfigPopover so it can float over anything. -->
105
+ <button
106
+ ref="methodBtnRef"
107
+ class="kh-recall-mode-btn"
108
+ @click="toggleConfig"
109
+ >
110
+ <span class="kh-recall-mode-icon">{{ methodIcon }}</span>
111
+ <span>{{ methodLabel }}</span>
112
+ <span class="kh-recall-mode-caret">▾</span>
113
+ </button>
114
+ </div>
115
+ <textarea
116
+ v-model="query"
117
+ class="kh-recall-textarea"
118
+ placeholder="请输入文本,建议使用简短的陈述句。"
119
+ maxlength="500"
120
+ />
121
+ <div class="kh-recall-input-footer">
122
+ <span class="kh-recall-char-count">
123
+ {{ charCount }}/500
124
+ </span>
125
+ <button
126
+ class="kh-btn kh-btn-primary"
127
+ :disabled="!canRun || loading"
128
+ @click="run"
129
+ >
130
+ 测试
131
+ </button>
132
+ </div>
133
+ </div>
134
+
135
+ <!-- 记录 -->
136
+ <div class="kh-recall-history">
137
+ <div class="kh-recall-history-title">记录</div>
138
+ <div v-if="history.length === 0" class="kh-recall-history-empty">
139
+ <div class="kh-recall-empty-icon-wrap">
140
+ <div class="kh-recall-empty-clock">🕐</div>
141
+ </div>
142
+ <div class="kh-recall-empty-text">最近无查询结果</div>
143
+ </div>
144
+ <div v-else class="kh-recall-history-list">
145
+ <div
146
+ v-for="h in history"
147
+ :key="h.id"
148
+ class="kh-recall-history-row"
149
+ @click="replay(h)"
150
+ >
151
+ <span class="kh-recall-history-method">{{ h.method }}</span>
152
+ <span class="kh-recall-history-query">{{ h.query }}</span>
153
+ <span class="kh-recall-history-count">{{ h.hitCount }} 命中</span>
154
+ <span class="kh-recall-history-at">{{ h.at }}</span>
155
+ </div>
156
+ </div>
157
+ </div>
158
+ </div>
159
+
160
+ <!-- RIGHT — hit results always render their title at the very top so the
161
+ panel doesn't waste the upper half on whitespace. Empty / loading /
162
+ populated states now share the same anchor. -->
163
+ <div class="kh-recall-right">
164
+ <div class="kh-recall-results-title">
165
+ 命中片段
166
+ <span v-if="hits.length > 0" class="kh-recall-results-count">
167
+ · {{ hits.length }} 个
168
+ </span>
169
+ </div>
170
+ <div v-if="hits.length === 0" class="kh-recall-right-empty">
171
+ <div class="kh-recall-empty-target">🎯</div>
172
+ <div class="kh-recall-empty-hint">召回测试结果显示在这里</div>
173
+ </div>
174
+ <div v-else class="kh-recall-results">
175
+ <div
176
+ v-for="(hit, i) in hits"
177
+ :key="hit.segmentId"
178
+ class="kh-recall-hit"
179
+ >
180
+ <div class="kh-recall-hit-head">
181
+ <span class="kh-recall-hit-tag">
182
+ {{ i + 1 }}
183
+ </span>
184
+ <span v-if="hit.documentName" class="kh-recall-hit-doc">
185
+ 📄 {{ hit.documentName }}
186
+ </span>
187
+ <span class="kh-recall-flex" />
188
+ <span class="kh-recall-hit-score">
189
+ 综合 {{ hit.score.toFixed(3) }}
190
+ </span>
191
+ </div>
192
+ <div class="kh-recall-hit-body">{{ hit.content }}</div>
193
+ </div>
194
+ </div>
195
+ </div>
196
+ </div>
197
+
198
+ <!-- Floating 检索设置 card — Teleport'd to <body>, positioned against the
199
+ anchor button. Keeps the panel layout untouched even when open. -->
200
+ <RetrievalConfigPopover
201
+ v-model:open="popoverOpen"
202
+ :trigger-el="methodBtnRef"
203
+ v-model="config"
204
+ :rerank-models="rerankModels"
205
+ :indexing-technique="indexingTechnique"
206
+ />
207
+ </div>
208
+ </template>
209
+
210
+ <style scoped>
211
+ .kh-recall {
212
+ display: flex;
213
+ flex-direction: column;
214
+ height: 100%;
215
+ padding: 14px 24px 20px;
216
+ }
217
+ .kh-recall-header {
218
+ margin-bottom: 10px;
219
+ }
220
+ .kh-recall-title {
221
+ font-size: 15px;
222
+ font-weight: 600;
223
+ color: #0f172a;
224
+ }
225
+ .kh-recall-sub {
226
+ margin-top: 2px;
227
+ font-size: 11px;
228
+ color: #94a3b8;
229
+ }
230
+
231
+ .kh-recall-body {
232
+ flex: 1;
233
+ display: grid;
234
+ /* Give the hit-results side a bit more room — the query editor + history
235
+ list on the left doesn't need half the width, and the hit cards benefit
236
+ from extra text width. */
237
+ grid-template-columns: minmax(340px, 5fr) minmax(0, 7fr);
238
+ gap: 20px;
239
+ overflow: hidden;
240
+ }
241
+
242
+ /* LEFT */
243
+ .kh-recall-left {
244
+ display: flex;
245
+ flex-direction: column;
246
+ gap: 22px;
247
+ min-width: 0;
248
+ }
249
+ .kh-recall-input-wrap {
250
+ border: 1.5px solid #6366f1;
251
+ border-radius: 10px;
252
+ padding: 12px 14px;
253
+ background: #fafbff;
254
+ }
255
+ .kh-recall-input-toolbar {
256
+ display: flex;
257
+ justify-content: space-between;
258
+ align-items: center;
259
+ margin-bottom: 8px;
260
+ }
261
+ .kh-recall-input-label {
262
+ font-size: 12px;
263
+ font-weight: 600;
264
+ color: #334155;
265
+ }
266
+ .kh-recall-mode-btn-wrap {
267
+ position: relative;
268
+ }
269
+ .kh-recall-mode-btn {
270
+ padding: 4px 10px;
271
+ border: 1px solid #e2e8f0;
272
+ border-radius: 6px;
273
+ background: #fff;
274
+ font-size: 11px;
275
+ color: #475569;
276
+ cursor: pointer;
277
+ display: inline-flex;
278
+ align-items: center;
279
+ gap: 6px;
280
+ }
281
+ .kh-recall-mode-btn:hover {
282
+ border-color: #cbd5e1;
283
+ }
284
+ .kh-recall-mode-icon {
285
+ color: #4338ca;
286
+ }
287
+ .kh-recall-mode-caret {
288
+ font-size: 9px;
289
+ color: #94a3b8;
290
+ }
291
+ .kh-recall-mode-menu {
292
+ position: absolute;
293
+ right: 0;
294
+ top: 30px;
295
+ z-index: 20;
296
+ min-width: 160px;
297
+ padding: 4px;
298
+ background: #fff;
299
+ border: 1px solid #e2e8f0;
300
+ border-radius: 8px;
301
+ box-shadow: 0 6px 20px rgba(15, 23, 42, 0.1);
302
+ }
303
+ .kh-recall-mode-item {
304
+ display: flex;
305
+ align-items: center;
306
+ gap: 8px;
307
+ padding: 6px 10px;
308
+ border-radius: 4px;
309
+ font-size: 12px;
310
+ color: #475569;
311
+ cursor: pointer;
312
+ }
313
+ .kh-recall-mode-item:hover {
314
+ background: #f8fafc;
315
+ }
316
+ .kh-recall-mode-item-active {
317
+ background: #eef2ff;
318
+ color: #4338ca;
319
+ }
320
+
321
+ .kh-recall-textarea {
322
+ width: 100%;
323
+ min-height: 140px;
324
+ padding: 8px 4px;
325
+ border: none;
326
+ outline: none;
327
+ resize: vertical;
328
+ background: transparent;
329
+ font-family: inherit;
330
+ font-size: 13px;
331
+ color: #0f172a;
332
+ line-height: 1.55;
333
+ }
334
+ .kh-recall-textarea::placeholder {
335
+ color: #94a3b8;
336
+ }
337
+
338
+ .kh-recall-input-footer {
339
+ display: flex;
340
+ justify-content: space-between;
341
+ align-items: center;
342
+ margin-top: 8px;
343
+ }
344
+ .kh-recall-char-count {
345
+ font-size: 11px;
346
+ color: #94a3b8;
347
+ }
348
+
349
+ .kh-btn {
350
+ padding: 6px 20px;
351
+ border: none;
352
+ border-radius: 6px;
353
+ font-size: 12px;
354
+ font-weight: 500;
355
+ cursor: pointer;
356
+ }
357
+ .kh-btn-primary {
358
+ background: linear-gradient(135deg, #6366f1, #4f46e5);
359
+ color: #fff;
360
+ }
361
+ .kh-btn-primary:disabled {
362
+ background: #cbd5e1;
363
+ cursor: not-allowed;
364
+ }
365
+
366
+ /* History */
367
+ .kh-recall-history-title {
368
+ font-size: 13px;
369
+ font-weight: 600;
370
+ color: #334155;
371
+ margin-bottom: 10px;
372
+ }
373
+ .kh-recall-history-empty {
374
+ display: flex;
375
+ flex-direction: column;
376
+ align-items: flex-start;
377
+ gap: 8px;
378
+ }
379
+ .kh-recall-empty-icon-wrap {
380
+ width: 42px;
381
+ height: 42px;
382
+ border-radius: 10px;
383
+ background: #f8fafc;
384
+ border: 1px solid #e2e8f0;
385
+ display: flex;
386
+ align-items: center;
387
+ justify-content: center;
388
+ }
389
+ .kh-recall-empty-clock {
390
+ font-size: 18px;
391
+ color: #94a3b8;
392
+ }
393
+ .kh-recall-empty-text {
394
+ font-size: 11px;
395
+ color: #94a3b8;
396
+ }
397
+ .kh-recall-history-list {
398
+ display: flex;
399
+ flex-direction: column;
400
+ gap: 4px;
401
+ }
402
+ .kh-recall-history-row {
403
+ display: grid;
404
+ grid-template-columns: 60px 1fr auto auto;
405
+ gap: 8px;
406
+ padding: 6px 8px;
407
+ border-radius: 6px;
408
+ cursor: pointer;
409
+ font-size: 11px;
410
+ align-items: center;
411
+ }
412
+ .kh-recall-history-row:hover {
413
+ background: #f8fafc;
414
+ }
415
+ .kh-recall-history-method {
416
+ padding: 1px 6px;
417
+ border-radius: 4px;
418
+ background: #eef2ff;
419
+ color: #4338ca;
420
+ font-size: 10px;
421
+ text-align: center;
422
+ }
423
+ .kh-recall-history-query {
424
+ color: #334155;
425
+ overflow: hidden;
426
+ text-overflow: ellipsis;
427
+ white-space: nowrap;
428
+ }
429
+ .kh-recall-history-count {
430
+ color: #64748b;
431
+ }
432
+ .kh-recall-history-at {
433
+ color: #94a3b8;
434
+ }
435
+
436
+ /* RIGHT — anchored to the top so both empty and populated states share the
437
+ same starting line as the query editor on the left. */
438
+ .kh-recall-right {
439
+ min-width: 0;
440
+ overflow-y: auto;
441
+ display: flex;
442
+ flex-direction: column;
443
+ gap: 10px;
444
+ padding: 4px 4px 8px;
445
+ background: #f8fafc;
446
+ border: 1px solid #f1f5f9;
447
+ border-radius: 10px;
448
+ }
449
+ .kh-recall-results-title {
450
+ padding: 10px 12px 6px;
451
+ font-size: 12px;
452
+ font-weight: 600;
453
+ color: #334155;
454
+ }
455
+ .kh-recall-results-count {
456
+ color: #94a3b8;
457
+ font-weight: 400;
458
+ }
459
+ .kh-recall-right-empty {
460
+ padding: 32px 12px 40px;
461
+ text-align: center;
462
+ color: #94a3b8;
463
+ }
464
+ .kh-recall-empty-target {
465
+ font-size: 38px;
466
+ opacity: 0.5;
467
+ }
468
+ .kh-recall-empty-hint {
469
+ margin-top: 10px;
470
+ font-size: 12px;
471
+ color: #94a3b8;
472
+ }
473
+ .kh-recall-results {
474
+ width: 100%;
475
+ padding: 0 10px 6px;
476
+ }
477
+ .kh-recall-hit {
478
+ padding: 10px 12px;
479
+ margin-bottom: 8px;
480
+ background: #fff;
481
+ border: 1px solid #e2e8f0;
482
+ border-radius: 8px;
483
+ }
484
+ .kh-recall-hit-head {
485
+ display: flex;
486
+ align-items: center;
487
+ gap: 8px;
488
+ font-size: 11px;
489
+ color: #64748b;
490
+ margin-bottom: 8px;
491
+ }
492
+ .kh-recall-hit-tag {
493
+ padding: 2px 8px;
494
+ background: #4338ca;
495
+ color: #fff;
496
+ border-radius: 4px;
497
+ font-weight: 600;
498
+ font-size: 10px;
499
+ }
500
+ .kh-recall-hit-doc {
501
+ color: #4338ca;
502
+ }
503
+ .kh-recall-hit-score {
504
+ color: #b45309;
505
+ font-weight: 600;
506
+ }
507
+ .kh-recall-flex {
508
+ flex: 1;
509
+ }
510
+ .kh-recall-hit-body {
511
+ font-size: 12px;
512
+ color: #334155;
513
+ line-height: 1.55;
514
+ }
515
+ </style>