Skip to content

Make managed agent hooks provider-independent#2176

Merged
gold-silver-copper merged 4 commits into
mainfrom
agent/non-generic-agent-hooks
Jul 17, 2026
Merged

Make managed agent hooks provider-independent#2176
gold-silver-copper merged 4 commits into
mainfrom
agent/non-generic-agent-hooks

Conversation

@gold-silver-copper

@gold-silver-copper gold-silver-copper commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

  • remove the completion-model generic from AgentHook, erased hook dispatch, and HookStack
  • expose canonical prompt, assistant content, usage, and message ID fields from managed completion and streaming response hooks
  • migrate agents, runners, extractors, examples, and provider cassette hooks while keeping direct provider APIs and MultiTurnStreamItem<R> generic
  • finalize managed streaming turns at provider EOF so StreamResponseFinish sees trailing silent metadata such as message IDs, while keeping IDs optional and rejecting post-final visible content
  • centralize streamed-turn normalization in canonical_choice() and cover interleaved reasoning, text, and tool content at the finish-hook boundary
  • document a concise provider-independent hook implementation and demonstrate canonical content, usage, and message IDs in request_hook
  • add regression coverage for multi-model hook reuse, canonical blocking/streaming parity, finish-hook cancellation/error ordering, extractor hooks, and composition semantics

Why

Managed hooks observe Rig's orchestration lifecycle, so coupling each hook implementation and hook stack to a provider model type adds boilerplate and leaks provider response types across the orchestration boundary. Canonical lifecycle events let one concrete hook attach to agents backed by different completion models while preserving typed raw responses on direct CompletionModel APIs.

For managed streaming, a provider's typed final payload is not necessarily stream EOF: silent metadata can follow it. Buffering the final item until EOF gives the hook and committed turn the same finalized canonical content and message ID without imposing provider-specific event ordering.

Impact

This is a breaking API simplification. Implementations change from impl<M: CompletionModel> AgentHook<M> for Hook to impl AgentHook for Hook. Managed completion and streaming response hooks now read prompt, content, usage, and message_id directly from their event rather than a typed provider response.

message_id remains optional. Managed streams accept silent message-ID metadata after the typed final payload, but reject visible assistant content after that payload as a malformed provider stream.

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all-targets --all-features -- -D warnings
  • CARGO_INCREMENTAL=0 cargo test
  • cargo doc --workspace --no-deps
  • cargo check -p rig-core --features wasm --target wasm32-unknown-unknown
  • cargo test -p rig-core --doc
  • cargo check -p request_hook
  • targeted streamed-turn, finish-hook, cross-model runner, extractor, OpenAI, Anthropic, and Gemini cassette tests
  • independent review of the complete 59-file diff against main; one post-final validation gap was found, fixed, retested, and the final review found no remaining issues

Workspace documentation succeeds with two existing unrelated rustdoc warnings in the Doubleword and Neo4j crates.

@gold-silver-copper
gold-silver-copper marked this pull request as ready for review July 17, 2026 19:19
@gold-silver-copper
gold-silver-copper added this pull request to the merge queue Jul 17, 2026
Merged via the queue into main with commit c050acf Jul 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant