|
| 1 | +<script setup lang="ts"> |
| 2 | +import type { ClientWebMcpState } from '../composables/client' |
| 3 | +import type { InvokeResult, RpcFunctionInfo } from '../connect' |
| 4 | +import { resolveWebMcpModelContext } from 'devframe/client' |
| 5 | +import { onMounted, onUnmounted, reactive, shallowRef } from 'vue' |
| 6 | +import { executeWebMcpTool, invokeClientFunction, listClientFunctions, loadWebMcpState } from '../composables/client' |
| 7 | +import { useRefreshProvider } from '../composables/refresh' |
| 8 | +import { useRpc } from '../composables/rpc' |
| 9 | +import ClientView from './ClientView.vue' |
| 10 | +
|
| 11 | +const rpc = useRpc() |
| 12 | +const functions = shallowRef<RpcFunctionInfo[] | null>(null) |
| 13 | +const webmcp = shallowRef<ClientWebMcpState | null>(null) |
| 14 | +const results = reactive<Record<string, InvokeResult | { ok: false, error: { name: string, message: string } }>>({}) |
| 15 | +const pending = reactive<Record<string, boolean>>({}) |
| 16 | +
|
| 17 | +async function fetchData(): Promise<void> { |
| 18 | + if (!rpc.value) |
| 19 | + return |
| 20 | + functions.value = listClientFunctions(rpc.value.client) |
| 21 | + webmcp.value = await loadWebMcpState(rpc.value.client) |
| 22 | +} |
| 23 | +
|
| 24 | +useRefreshProvider(fetchData) |
| 25 | +let unsubscribe: (() => void) | undefined |
| 26 | +onMounted(() => { |
| 27 | + void fetchData() |
| 28 | + // Client functions register locally at any time; follow the collector. |
| 29 | + unsubscribe = rpc.value?.client.onChanged(() => void fetchData()) |
| 30 | +}) |
| 31 | +onUnmounted(() => unsubscribe?.()) |
| 32 | +
|
| 33 | +async function onInvoke(fn: RpcFunctionInfo, parsedArgs: unknown[]): Promise<void> { |
| 34 | + if (!rpc.value) |
| 35 | + return |
| 36 | + pending[fn.name] = true |
| 37 | + try { |
| 38 | + results[fn.name] = await invokeClientFunction(rpc.value.client, fn.name, parsedArgs) |
| 39 | + } |
| 40 | + finally { |
| 41 | + pending[fn.name] = false |
| 42 | + } |
| 43 | +} |
| 44 | +
|
| 45 | +async function onInvokeTool(name: string, parsedArgs: Record<string, unknown>): Promise<void> { |
| 46 | + const modelContext = resolveWebMcpModelContext() |
| 47 | + const tool = webmcp.value?.tools.find(t => t.name === name) |
| 48 | + if (!modelContext || !tool) |
| 49 | + return |
| 50 | + const key = `webmcp:${name}` |
| 51 | + pending[key] = true |
| 52 | + try { |
| 53 | + results[key] = await executeWebMcpTool(modelContext, tool, parsedArgs) |
| 54 | + } |
| 55 | + finally { |
| 56 | + pending[key] = false |
| 57 | + } |
| 58 | +} |
| 59 | +</script> |
| 60 | + |
| 61 | +<template> |
| 62 | + <ClientView |
| 63 | + :functions="functions" |
| 64 | + :webmcp="webmcp" |
| 65 | + :results="results" |
| 66 | + :pending="pending" |
| 67 | + @invoke="onInvoke" |
| 68 | + @invoke-tool="onInvokeTool" |
| 69 | + /> |
| 70 | +</template> |
0 commit comments