Agno 适配
如果你的后端就是 Agno,最推荐的接法是:
- 继续返回官方 Agno 事件
- 聊天页面优先用
useAgnoChatSession() - 需要 starter 级控制时再用
createAgnoAdapter() - 不为了前端额外发明一层新协议
默认映射了什么
createAgnoProtocol() 当前默认会处理:
RunStarted映射成run.startRunContent作为 markdown 流式文本追加ToolCallStarted关闭当前文本分段,再创建工具 blockToolCallCompleted更新工具结果RunCompleted收尾当前文本分段并结束 runRunCancelled/RunError/Error中止流并标记 run/error
额外还做了两件很关键的事:
- 工具前后的文本会自动分段,避免全部拼到同一个 block
- 工具结果如果是常见的 Python
repr风格字符串,会尽量恢复成对象
聊天页面最常见的接法
ts
import {
defineAgnoToolComponents,
useAgnoChatSession
} from 'agentdown';
import WeatherToolCard from './WeatherToolCard.vue';
const prompt = ref('帮我查一下北京天气');
const session = useAgnoChatSession<string>({
source: 'http://127.0.0.1:8000/api/stream/agno',
input: prompt,
conversationId: 'session:weather-demo',
title: 'Agno 助手',
tools: defineAgnoToolComponents({
'tool.weather': {
match: ['weather', '天气'],
mode: 'includes',
component: WeatherToolCard
}
}),
surface: {
draftPlaceholder: false
}
});
await session.send();vue
<RunSurface
:runtime="session.runtime"
v-bind="session.surface"
/>和旧写法相比,这里少了三层重复胶水代码:
- 不需要自己
defineAgnoPreset() - 不需要手动
preset.createSession() - 不需要再额外包一层
useBridgeTransport() - 不需要再手写
mode / headers / body / JSON.stringify
如果你要的是 starter 级控制,而不是聊天页最短接法,再往下切到 createAgnoAdapter() + useAdapterSession() 就可以。
按工具名挂组件
最常见的需求就是:
lookup_weather显示天气卡片search_docs显示文档搜索卡片
最省事的写法还是直接用 defineAgnoToolComponents():
ts
// 同一份配置会同时产生 toolRenderer 和 renderers。
const agnoTools = defineAgnoToolComponents({
'tool.weather': {
match: ['lookup_weather', 'weather', '天气'],
mode: 'includes',
component: WeatherToolCard
},
'tool.search-docs': {
match: ['search_docs', /doc|search/i],
component: SearchDocsCard
}
});它会同时生成:
agnoTools.toolRendereragnoTools.renderers
所以你不需要一边在协议里写工具名判断,一边在 surface 里再维护一份组件表。
如果你想做跨框架共享配置,也可以直接用通用 DSL toolByName(),再把结果塞给 createAgnoAdapter({ tools })。
按事件名挂组件
如果你还想做:
- 某个 Agno 原始事件到了就额外渲染组件
- 同一个组件随着 SSE 事件持续 patch
可以用 defineAgnoEventComponents(),或者直接用通用 DSL eventToBlock()。
ts
import {
createAgnoAdapter,
// 让某些 Agno 原始事件直接渲染成组件。
defineAgnoEventComponents,
useAdapterSession
} from 'agentdown';
import WeatherSummaryCard from './WeatherSummaryCard.vue';
// 当工具完成事件到来时,补一张业务摘要卡片。
const agnoEvents = defineAgnoEventComponents({
'event.weather-summary': {
on: 'tool_call_completed',
component: WeatherSummaryCard,
resolve: ({ event }) => ({
id: 'event:block:weather-summary',
groupId: 'turn:weather',
data: {
payload: event
}
})
}
});
// starter adapter 会自动把主协议和事件 helper 组合起来。
const agno = createAgnoAdapter({
events: agnoEvents
});
const session = useAdapterSession(agno);这里默认使用 patch 模式而不是 upsert,原因是 SSE 场景里同一个组件连续更新更常见,而 patch 不会把已有 block 反复挪到列表尾部。
用户可以自定义什么
defaultRunTitle
ts
// 也可以直接写死一个标题。
defaultRunTitle: 'Agno 助手'或者:
ts
// 或者根据当前 packet 动态决定标题。
defaultRunTitle: (packet) => packet.agent_name ?? '通用助手'toolRenderer
最常用的自定义项,用来决定工具块使用哪个 renderer key。
groupId / blockId / streamId
如果你想和现有消息模型、埋点模型或缓存模型对齐,可以改这些 id 规则。
recordEvents
调试或做回放时可打开:
ts
// 打开后,原始 Agno 事件也会写进 runtime history 里。
recordEvents: truesurface
可以继续覆写:
renderersdraftPlaceholderbuiltinComponentsmessageShellsperformance
什么时候不用默认 Agno protocol
只有两种情况建议你自己往下拆:
- 你的后端对官方 Agno 事件做了很重的二次封装
- 你要把 Agno 事件和其他来源的自定义事件混在同一条流里统一消费
这时通常的做法也不是完全推倒重来,而是:
createAgnoProtocol()保留主协议composeProtocols()叠加额外协议
这样既保留官方事件支持,也能继续扩展业务块。