Hướng dẫn tích hợp
Hướng dẫn này đi qua một tích hợp @agentic-ui hoàn chỉnh cho app Vue: khai báo capability, kết nối chúng với một LLM qua proxy, và yêu cầu người dùng duyệt các hành động rủi ro. Các phiên bản chạy được của tích hợp này nằm ở playground/ và examples/.
Các mảnh ghép kết nối thế nào
Vue component ──useAgentCapability──▶ registry (core)
│
server proxy ──streamText(tools)──▶ LLM │ the model returns tool-calls
▲ ▼
└──────── bindRegistryToChat ── registry.execute (validate→permission
→confirmation→execute) ──▶ resultAPI key không bao giờ vào browser. Client gửi {messages, tools} tới proxy của bạn, chỉ kèm schema của các tool. Proxy chạy streamText và stream các tool-call ngược về client. Registry thực thi các call đó và trả kết quả về stream.
1. Cài đặt
pnpm add @agentic-ui/vue @agentic-ui/client ai @ai-sdk/openai@agentic-ui/core, /schema, và /protocol được cài kèm theo dạng dependency. SDK ai chỉ là peer dependency của @agentic-ui/client.
2. Đăng ký plugin
// main.ts
import { createApp } from 'vue'
import { createAgenticUi } from '@agentic-ui/vue'
createApp(App).use(createAgenticUi()).mount('#app')Bước này cung cấp một registry duy nhất cho toàn app. Truy cập nó từ bất kỳ component nào bằng useAgent().
3. Khai báo capability
Một capability là một hành động có type, có mô tả, và gắn nhãn risk. Khi khai báo trong component, nó đăng ký lúc mount và được dispose lúc unmount.
import { useAgentCapability } from '@agentic-ui/vue'
useAgentCapability({
name: 'todos.add', // dotted namespaces are fine
description: 'Add a new todo item.', // the model reads this — be clear
inputSchema: {
type: 'object',
properties: { text: { type: 'string' } },
required: ['text'],
},
risk: 'mutating', // 'read' | 'mutating' | 'destructive'
execute: ({ text }: { text: string }) => { todos.push({ text, done: false }) },
})riskđiều khiển việc xác nhận:readchạy ngay lập tức, cònmutatingvàdestructivecần được duyệt (xem bước 6). Muốn đổi hành vi này cho một capability riêng lẻ, truyền vào mộtconfirmationpolicy.inputSchemalà JSON Schema (tập con draft-07). Mọi call đều được validate theo schema này trước khiexecutechạy. Payload không hợp lệ trả vềinvalid, kèm thông tin để model tự sửa. Bạn cũng có thể truyền schema zod, adapter sẽ chuyển đổi.- Định nghĩa có thể là ref/getter — cập nhật schema khi UI thay đổi (ví dụ enum các field đang hiển thị trên màn hình), và revision của catalog sẽ tăng theo.
Để cung cấp giá trị hiện tại theo yêu cầu mà không phải nhét toàn bộ state của app vào context của model, hãy mở một capability risk read. Model sẽ gọi nó khi cần dữ liệu.
4. Server proxy (nơi giữ key)
Server proxy là một Node handler ~50 dòng. Nó dùng catalogToToolSet để map các schema tool gửi lên thành một ToolSet của AI SDK, rồi chạy streamText:
import { convertToModelMessages, streamText } from 'ai'
import { createOpenAI } from '@ai-sdk/openai'
import { catalogToToolSet } from '@agentic-ui/client'
const openai = createOpenAI({
apiKey: process.env.OPENAI_API_KEY, // stays server-side
baseURL: process.env.OPENAI_BASE_URL, // optional: an OpenAI-compatible gateway
})
const model = openai.chat(process.env.OPENAI_MODEL ?? 'gpt-4o-mini')
// per request: { messages, tools } from the client
const result = streamText({
model,
messages: convertToModelMessages(messages),
tools: catalogToToolSet(tools), // schema-only; execution stays client-side
})
return result.toUIMessageStreamResponse()Xem playground/server/index.ts để có handler hoàn chỉnh, bao gồm cả một permission stub.
5. Client transport
Bind chat vào registry để mọi tool-call stream về đều chạy qua pipeline thực thi. Ở mỗi request gửi đi, dùng binding để serialize catalog; snapshot revision của nó cho phép kiểm tra stale:
import { bindRegistryToChat, sendAutomaticallyWhen } from '@agentic-ui/client'
import { DefaultChatTransport } from 'ai'
let binding
const chat = new YourChat({
transport: new DefaultChatTransport({
api: '/agent/chat',
prepareSendMessagesRequest: ({ messages }) => ({
body: { messages, tools: binding.buildRequestTools().tools },
}),
}),
sendAutomaticallyWhen, // resend automatically once tool results are in
})
binding = bindRegistryToChat(chat, registry)YourChat có thể là bất kỳ chat AI SDK nào có state backed bằng Vue ref, để template re-render theo tiến trình stream. Implementation tái sử dụng được nằm ở playground/src/agent-chat.ts.
6. Luồng duyệt
Các call mutating và destructive bị chặn lại cho đến khi người dùng duyệt đúng payload đó. Hiển thị hàng đợi chờ duyệt bằng useConfirmationQueue:
<script setup lang="ts">
import { useConfirmationQueue } from '@agentic-ui/vue'
const queue = useConfirmationQueue()
</script>
<template>
<div v-for="req in queue.pending.value" :key="req.request.callId">
{{ req.request.descriptor.name }} — digest {{ req.request.digest.slice(0, 8) }}
<button @click="req.approve('digest')">Approve</button>
<button @click="req.deny('Not now')">Deny</button>
</div>
</template>Duyệt với 'digest' sẽ ghi nhớ đúng payload đó. Một call giống hệt sẽ không hỏi lại, nhưng chỉ cần lệch một byte là sẽ hỏi. Nếu người dùng từ chối, call kết thúc với trạng thái unconfirmed, model nhận kết quả đó, và execute không chạy.
7. Xem catalog đang chạy
useAgent().entries là reactive và phản ánh các capability đang mount. Nhờ đó một capability inspector hay debug panel luôn đồng bộ khi các view mount và unmount:
const { entries, registry } = useAgent()
// registry.onAudit(e => timeline.push(e)) // received→validated→…→executed8. Mở rộng catalog
Với bộ tool nhỏ, gửi tất cả tool bằng mode mặc định direct. Khi vượt quá vài chục tool, chọn mode qua buildRequestTools(registry, { mode }):
{ mode: 'scoped', scopes }— chỉ gửi các capability trong những scope được chỉ định.{ mode: 'meta-tools' }— chỉ gửi ba tool (agent.search_capabilities,agent.describe,agent.execute). Model tự search và lấy mô tả khi cần, cònagent.executechạy tool bên dưới qua pipeline chuẩn. Việc xác nhận vẫn dùng digest của tool thật.
Gateway & provider
- Trỏ proxy tới bất kỳ gateway OpenAI-compatible nào (9Router, LiteLLM, one-api) qua
OPENAI_BASE_URL; key vẫn nằm phía server. - Dùng
openai.chat(...)(Chat Completions). Responses API mặc định làm lệch thread tool-call id khi đi qua các gateway kiểu này. - Tên tool gửi cho model được chuẩn hoá về
^[a-zA-Z0-9_-]+$(toWireName) vì provider từ chối tên có dấu chấm. Trước khi thực thi, client map ngược về tên capability gốc, nên bạn cứ viếttodos.addnhư bình thường.
Kiểm thử
Bạn có thể test một capability mà không cần LLM; xem Test capability của bạn. Mỗi example app cũng kèm một test end-to-end với mock-LLM theo kịch bản mà bạn có thể tái sử dụng.