接线:把 agent 跑起来时已经有的观察点接到发射器上。
三个采集点,各自有不可替代的理由(docs/agent-runtime-design.md §4.9):
| 采集点 | 拿到什么 | 为什么非它不可 |
|---|---|---|
:on-token | 正文 / 思维 token 增量 | 唯一的 token 粒度出口 |
:on-llm-result callback | ChatResponse——含 tool-call :id | :on-tool-call 的签名是 (fn [tool-name args]),:tool 链的 ToolRequest 是 {:function :args :context}——两个都没有 id,而事件流要靠 id 把 start/args/result 串起来。而且 :tool 链跑在并行任务里 |
:iteration 链 | 本轮 delta(带 :tool-call-id 的结果消息)+ 折叠后的 context | 每轮一次、在循环线程上、手里有完整的本轮消息 |
不新增 callback,也不改 react——三个点全是现成的。
接线:把 agent 跑起来时**已经有的**观察点接到发射器上。
三个采集点,各自有不可替代的理由(docs/agent-runtime-design.md §4.9):
| 采集点 | 拿到什么 | 为什么非它不可 |
|---|---|---|
| `:on-token` | 正文 / 思维 token 增量 | 唯一的 token 粒度出口 |
| `:on-llm-result` callback | ChatResponse——**含 tool-call `:id`** | `:on-tool-call` 的签名是 `(fn [tool-name args])`,`:tool` 链的 ToolRequest 是 `{:function :args :context}`——**两个都没有 id**,而事件流要靠 id 把 start/args/result 串起来。而且 `:tool` 链跑在并行任务里 |
| `:iteration` 链 | 本轮 delta(带 `:tool-call-id` 的结果消息)+ 折叠后的 context | 每轮一次、在循环线程上、手里有完整的本轮消息 |
**不新增 callback**,也不改 react——三个点全是现成的。(attach agent em)给一个 agent 挂上采集::iteration filter + :on-llm-result 回调。
create-agent 明确拒绝 :filters(agent 层只暴露 :callbacks),所以这里
走 flt/with-filters 在已建好的 ChatClient 上追加——它同步重编 hooks,
比 assoc :filters 少一次每 invoke 的重编译。
给一个 agent 挂上采集:`:iteration` filter + `:on-llm-result` 回调。 `create-agent` 明确拒绝 `:filters`(agent 层只暴露 `:callbacks`),所以这里 走 `flt/with-filters` 在**已建好的 ChatClient** 上追加——它同步重编 hooks, 比 `assoc :filters` 少一次每 invoke 的重编译。
(compose-callbacks user-callbacks agui-callbacks)把 agui 的采集回调与用户自己的回调合成一份。
callbacks 只有一个槽,agui 要占 :on-llm-result,用户也想挂自己的——
合成器就是几行,不进框架(design-principles §1:用户几行就等价的不长 API 面)。
顺序:先用户后 agui,且各自吞异常(cb/invoke 的语义在外层照旧生效)。
把 agui 的采集回调与用户自己的回调合成一份。 callbacks 只有一个槽,agui 要占 `:on-llm-result`,用户也想挂自己的—— 合成器就是几行,**不进框架**(design-principles §1:用户几行就等价的不长 API 面)。 顺序:先用户后 agui,且各自吞异常(`cb/invoke` 的语义在外层照旧生效)。
(iteration-filter em):iteration 链上的采集 filter。
请求侧:声明本轮的消息 id(真到第一个 token 才发 :message/started),
并补发上一轮遗留的工具结果——resume 那半批(审批后执行的 pending 工具)
不经过本链,它的结果是作为下一轮的 delta 进来的,只有在请求侧才捞得到。
响应侧:发本轮工具结果与状态快照。必须走 flt/fmap——异步驱动下终端
返回的是 deferred(filter-chain-design §2.6.4)。
`:iteration` 链上的采集 filter。 请求侧:声明本轮的消息 id(真到第一个 token 才发 `:message/started`), 并补发**上一轮遗留**的工具结果——resume 那半批(审批后执行的 pending 工具) 不经过本链,它的结果是作为**下一轮的 delta** 进来的,只有在请求侧才捞得到。 响应侧:发本轮工具结果与状态快照。**必须走 `flt/fmap`**——异步驱动下终端 返回的是 deferred(filter-chain-design §2.6.4)。
(on-llm-result em):on-llm-result 回调:收本轮 LLM 的产出。
顺序按 AG-UI 的块语义:先把这一轮的文本消息收口(流式下 token 已逐条发过,
这里只补 :message/ended;非流式下整段文本在这里一次性补出),再发工具调用
的 start → args → end(结果在工具真跑完之后由 :iteration 链发)。
`:on-llm-result` 回调:收本轮 LLM 的产出。 顺序按 AG-UI 的块语义:先把这一轮的文本消息收口(流式下 token 已逐条发过, 这里只补 `:message/ended`;非流式下整段文本在这里一次性补出),再发工具调用 的 `start → args → end`(结果在工具真跑完之后由 `:iteration` 链发)。
(token-fn em):on-token 回调:把增量 token 变成事件。
on-token 收到的是 {:token "…"} 或 {:reasoning-token "…"}(无 :accumulated,
要全文自行累积——docs/token-stream-filter-design.md)。
`:on-token` 回调:把增量 token 变成事件。
`on-token` 收到的是 `{:token "…"}` 或 `{:reasoning-token "…"}`(无 `:accumulated`,
要全文自行累积——docs/token-stream-filter-design.md)。cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |