@v-miniapp/ai
v0.0.24
Published
**@v-miniapp/ai** là bộ thư viện hỗ trợ xây dựng AI App cho V-App: phía server cung cấp class `McpServer` bao trọn Express + MCP SDK, phía widget cung cấp React hooks và bridge để giao tiếp với host AI.
Readme
@v-miniapp/ai
@v-miniapp/ai là bộ thư viện hỗ trợ xây dựng AI App cho V-App: phía server cung cấp class McpServer bao trọn Express + MCP SDK, phía widget cung cấp React hooks và bridge để giao tiếp với host AI.
📚 Tài liệu chính thức: Tổng quan về AI App
Cài đặt
# PNPM
pnpm install @v-miniapp/ai
# YARN
yarn install @v-miniapp/ai
# NPM
npm install @v-miniapp/aiCác entry point
Package được tách thành 3 subpath import để tránh kéo theo dependency không cần thiết:
| Import | Môi trường | Mục đích |
| ---------------------- | --------------- | ----------------------------------------------------------------------- |
| @v-miniapp/ai/server | Node.js | Khởi tạo MCP server, đăng ký tool / resource / prompt / skill |
| @v-miniapp/ai/web | Browser (React) | Hooks và components để xây widget chạy bên trong host AI |
| @v-miniapp/ai/apis | Browser | Truy cập trực tiếp adaptor (callTool, openDeeplink, reportAnalytics, …) |
Phía Server — @v-miniapp/ai/server
import {
McpServer,
McpTool,
createStructuredResult,
} from '@v-miniapp/ai/server'
import { z } from 'zod'
const listTodos = new McpTool({
name: 'list-todos',
resourceName: 'todo-widget',
config: {
title: 'List todos',
description: 'Trả về danh sách todo hiện tại',
inputSchema: {},
},
handler: async () => {
const todos = await db.todos.findMany()
return createStructuredResult({ todos })
},
})
const addTodo = new McpTool({
name: 'add-todo',
resourceName: 'todo-widget',
config: {
title: 'Add todo',
inputSchema: { text: z.string().min(1) },
},
handler: async ({ text }) => {
const todos = await db.todos.create({ text })
return createStructuredResult({ todos })
},
})
const server = new McpServer()
.registerResources(['todo-widget'])
.registerSkills(['expert-todo'])
.registerTool(listTodos)
.registerTool(addTodo)
await server.run()Phía Widget — @v-miniapp/ai/web
import {
AppProvider,
useToolInfo,
useCallTool,
useWidgetState,
getStructuredResult,
} from '@v-miniapp/ai/web'
function TodoWidget() {
// Quan sát tool do AI gọi (passive)
const toolInfo = useToolInfo<'list-todos'>()
const data = getStructuredResult(toolInfo)
// Gọi tool từ widget (active)
const addTool = useCallTool('add-todo')
// State được sync với host
const [filters, setFilters] = useWidgetState<{ query: string }>({ query: '' })
if (toolInfo.isPending) return <Skeleton />
if (toolInfo.isError) return <ErrorView error={toolInfo.error} />
return (
<div>
<input
value={filters.query}
onChange={e => setFilters({ query: e.target.value })}
/>
<ul>
{data?.todos.map(t => (
<li key={t.id}>{t.text}</li>
))}
</ul>
<button
disabled={addTool.isPending}
onClick={() => addTool.callTool({ text: 'Buy milk' })}>
{addTool.isPending ? 'Adding…' : 'Add'}
</button>
</div>
)
}
export default function App() {
return (
<AppProvider loadingComponent={() => <Skeleton />}>
<TodoWidget />
</AppProvider>
)
}