外观
Client 端插件
创建插件
typescript
const myPlugin = {
hooks: {
beforeCall: async (ctx) => { ... },
afterCall: async (ctx, stream) => { return stream },
}
}
client.use(myPlugin)Hooks
beforeCall
调用技能前:
typescript
{
beforeCall: async (ctx) => {
// 注入认证
ctx.metadata['authorization'] = `Bearer ${token}`
// 注入追踪 ID
ctx.metadata['x-trace-id'] = generateTraceId()
console.log('Calling:', ctx.skill)
}
}afterCall
调用完成后(必须返回 stream):
typescript
{
afterCall: async (ctx, stream) => {
console.log('Connected to', ctx.skill)
return stream
}
}onError
错误处理:
typescript
{
onError: async (ctx, error) => {
console.error('Failed:', ctx.skill, error.message)
await reportError(error)
}
}常用插件示例
日志插件
typescript
const createLoggingPlugin = () => ({
hooks: {
beforeCall: async (ctx) => {
console.log('[Client] Calling', ctx.skill)
ctx.startTime = Date.now()
},
afterCall: async (ctx, stream) => {
console.log('[Client] Connected to', ctx.skill)
return stream
},
onError: async (ctx, error) => {
const duration = Date.now() - ctx.startTime
console.error(`[Client] ${ctx.skill} failed after ${duration}ms:`, error)
}
}
})认证插件
typescript
const createAuthPlugin = (getToken: () => Promise<string>) => ({
hooks: {
beforeCall: async (ctx) => {
const token = await getToken()
ctx.metadata['authorization'] = `Bearer ${token}`
}
}
})
// 使用
client.use(createAuthPlugin(async () => {
return localStorage.getItem('token')
}))追踪插件
typescript
const createTracingPlugin = (serviceName: string) => ({
hooks: {
beforeCall: async (ctx) => {
const traceId = ctx.metadata['x-trace-id'] || generateTraceId()
const spanId = generateSpanId()
ctx.metadata['x-trace-id'] = traceId
ctx.metadata['x-span-id'] = spanId
ctx.traceInfo = { traceId, spanId, startTime: Date.now() }
},
afterCall: async (ctx, stream) => {
const { traceId, spanId, startTime } = ctx.traceInfo
// 包装 stream 记录完成时间
const originalIterator = stream[Symbol.asyncIterator].bind(stream)
stream[Symbol.asyncIterator] = async function* () {
try {
for await (const msg of originalIterator()) {
yield msg
}
} finally {
reportSpan({
service: serviceName,
traceId,
spanId,
skill: ctx.skill,
duration: Date.now() - startTime
})
}
}
return stream
}
}
})组合多个插件
typescript
const client = createAgentClient(config)
.use(createLoggingPlugin())
.use(createAuthPlugin(getToken))
.use(createTracingPlugin('web-client'))
// 执行顺序:
// beforeCall: logging → auth → tracing
// afterCall: logging → auth → tracing
// onError: logging → auth → tracing浏览器使用
typescript
import { createAgentClient } from '@multi-agent/a2a/browser'
const client = createAgentClient(config)
.use(createLoggingPlugin())
.use(createAuthPlugin(getToken))