AgentCentralStage.vue
1 <script setup> 2 import { useMcpStore, getServers } from '@/renderer/store/mcp' 3 import { useAgentStore } from '@/renderer/store/agent' 4 import { useI18n } from 'vue-i18n' 5 import { v4 as uuidv4 } from 'uuid' 6 import { ref, watch, onMounted, computed } from 'vue' 7 const mcpStore = useMcpStore() 8 const agentStore = useAgentStore() 9 const { t } = useI18n() 10 11 const selectedTree = computed({ 12 get() { 13 return agentStore.getRevised?.selectedNode 14 }, 15 set(value) { 16 console.log('Selected tools', value) 17 if (agentStore.getRevised) { 18 agentStore.getRevised.selectedNode = value 19 } 20 } 21 }) 22 23 const items = ref([ 24 { 25 id: 1, 26 name: computed(() => t('agent.all')), 27 children: [] 28 } 29 ]) 30 31 watch( 32 () => agentStore.allTools, 33 (val) => { 34 if (!agentStore.hasTools) { 35 return 36 } 37 console.log('Tools Updated', val) 38 const flatChildren = [] 39 const children = val 40 .filter((serverType) => serverType.tools && serverType.tools.length > 0) 41 .map((serverType) => { 42 const serverNode = { 43 id: serverType.server, 44 name: serverType.server, 45 children: serverType.tools.map((tool) => { 46 const toolId = agentStore.genId(serverType.server, tool.name) 47 const toolNode = { 48 id: toolId, 49 server: serverType.server, 50 name: tool.name 51 } 52 flatChildren.push(toolId) 53 return toolNode 54 }) 55 } 56 return serverNode 57 }) 58 const rootObj = items.value[0] 59 rootObj.children = children 60 items.value = [rootObj] 61 62 agentStore.agents.forEach((agent) => { 63 const newSelectedNode = agent.selectedNode.filter((node) => { 64 return flatChildren.includes(node) 65 }) 66 agent.selectedNode = newSelectedNode 67 }) 68 } 69 ) 70 71 watch( 72 () => mcpStore.version, 73 (_val) => { 74 load() 75 } 76 ) 77 78 onMounted(() => { 79 load() 80 }) 81 82 function load() { 83 const mcpServers = getServers() 84 const mcpKeys = Object.keys(mcpServers) 85 // Create an array of Promises 86 const toolPromises = mcpKeys.map((key) => { 87 const toolsListFunction = mcpServers[key]?.tools?.list 88 if (typeof toolsListFunction === 'function') { 89 // Ensure that toolsListFunction() returns a Promise 90 return Promise.resolve(toolsListFunction()).then((tools) => ({ 91 server: key, 92 ...tools 93 })) 94 } else { 95 // If toolsListFunction is not a function, return an object with content as null 96 return Promise.resolve({ 97 name: key, 98 tools: [] 99 }) 100 } 101 }) 102 103 console.log(toolPromises) 104 105 // Return a Promise that resolves when all toolPromises are resolved 106 107 return Promise.all(toolPromises).then((data) => { 108 console.log(data) 109 agentStore.allTools = data 110 }) 111 } 112 113 function onClickClose(selection) { 114 selectedTree.value = selectedTree.value.filter((item) => item !== selection) 115 } 116 117 function handleNameUpdate() { 118 if (!agentStore.getRevised.name) { 119 agentStore.getRevised.name = `Agent ${uuidv4()}` 120 } 121 122 if (agentStore.getUnrevised.find((agent) => agent.name === agentStore.getRevised.name)) { 123 agentStore.getRevised.name = `Agent ${uuidv4()}` 124 } 125 } 126 </script> 127 128 <template> 129 <!-- <v-btn @click="console.log(agentStore.allTools)"></v-btn> --> 130 <div v-if="agentStore.getRevised" :key="agentStore.getRevised"> 131 <v-card :title="$t('agent.config')"> 132 <v-divider></v-divider> 133 <v-text-field 134 v-model="agentStore.getRevised.name" 135 density="compact" 136 variant="outlined" 137 class="px-6 pt-5" 138 :label="$t('setting.name')" 139 @blur="handleNameUpdate" 140 ></v-text-field> 141 </v-card> 142 143 <v-confirm-edit 144 v-model="agentStore.getRevised.prompt" 145 :cancel-text="$t('agent.cancel')" 146 :ok-text="$t('agent.save')" 147 > 148 <template #default="{ model: proxyModel, actions, isPristine }"> 149 <v-card class="mt-4" :title="$t('agent.prompt')"> 150 <v-divider></v-divider> 151 <template #text> 152 <v-textarea 153 v-model="proxyModel.value" 154 class="mx-2 mt-2" 155 auto-grow 156 variant="solo-filled" 157 :error-messages="isPristine ? '' : 'Please save'" 158 ></v-textarea> 159 </template> 160 <template #actions> 161 <v-spacer></v-spacer> 162 <component :is="actions" color="primary"></component> 163 </template> 164 </v-card> 165 </template> 166 </v-confirm-edit> 167 168 <v-alert 169 v-if="!agentStore.hasTools" 170 border="top" 171 type="warning" 172 variant="outlined" 173 prominent 174 class="mt-4" 175 > 176 {{ $t('agent.no-tools') }} 177 </v-alert> 178 <v-card v-else class="mt-4" :title="$t('agent.tools')"> 179 <v-row density="compact"> 180 <v-divider></v-divider> 181 <v-treeview 182 v-model:selected="selectedTree" 183 :items="items" 184 :load="load" 185 class="flex-1-0" 186 false-icon="mdi-bookmark-outline" 187 indeterminate-icon="mdi-bookmark-minus" 188 item-title="name" 189 item-value="id" 190 select-strategy="classic" 191 true-icon="mdi-bookmark" 192 selectable 193 ></v-treeview> 194 </v-row> 195 196 <v-row density="compact"> 197 <v-divider></v-divider> 198 <v-card-text> 199 <div 200 v-if="selectedTree.length === 0" 201 class="text-h6 font-weight-light text-grey pa-4 text-center" 202 > 203 {{ $t('agent.selected') }} 204 </div> 205 <div class="d-flex flex-wrap ga-1"> 206 <v-scroll-x-transition group hide-on-leave> 207 <div v-for="(selection, index) in selectedTree" :key="index"> 208 <v-chip 209 v-if="selection" 210 :key="selection" 211 :text="agentStore.getId(selection).name" 212 color="grey" 213 size="small" 214 border 215 closable 216 label 217 @click="console.log(selection, index)" 218 @click:close="onClickClose(selection)" 219 > 220 <template #prepend> 221 <v-avatar 222 :text="agentStore.getAbbr(agentStore.getId(selection).server)" 223 :color="agentStore.getColor(selection)" 224 start 225 variant="plain" 226 > 227 </v-avatar> 228 </template> 229 </v-chip> 230 </div> 231 </v-scroll-x-transition> 232 </div> 233 </v-card-text> 234 </v-row> 235 </v-card> 236 </div> 237 </template>