Skip to content

Proposal: declarative AI agent / chat support — handlers as LLM tools, conversation as saga #4226

Description

@jeremydmiller

Proposal for a first-class, declarative way to build LLM chat/agent features on Wolverine, so agent workloads get the same durability, observability, and testability as every other message.

Sketch

Handlers as tools. An [AgentTool] attribute on a message type (or handler) generates the LLM tool schema from the message signature — the same reflection/codegen machinery that already builds HTTP endpoint metadata. When the model calls a tool, the call is dispatched as a real Wolverine message through IMessageBus: durable, retried, outbox-enrolled, observable. The agent loop is just another handler chain.

Conversation as a saga. A chat session is stateful, long-lived, and event-driven — exactly what sagas model:

opts.AddAgent<SupportAgent>(a => a
    .Model("claude-sonnet-5")
    .SystemPrompt(...)
    .Tools(typeof(LookupOrder), typeof(IssueRefund)));

Each turn and each tool invocation is a message; the conversation's history is the saga's stream. Streaming deltas ride the existing SignalR transport.

Provider seam. Microsoft.Extensions.AI's IChatClient is the obvious abstraction so Anthropic/OpenAI/local models plug in without Wolverine taking a vendor dependency.

Why in Wolverine rather than app code

  • Tool calls that mutate state get the transactional inbox/outbox for free — an agent's side effects stop racing its narration.
  • Retries/error policies apply to flaky model calls like any other endpoint.
  • Every agent decision is an envelope: correlation/causation chains answer "what did the agent do, what did it see, in what order" with infrastructure that already exists — observability tooling lights up with agent activity with no extra work.
  • Handlers-as-tools are unit-testable without a model in the loop, same as handlers-as-handlers.

Open questions

  • Loop ownership: does Wolverine run the model-call loop (a built-in agent runtime) or only provide the tool-dispatch + saga plumbing while the app owns the loop?
  • Tool-call authorization: per-tool gating analogous to HTTP auth policies.
  • Token/streaming ergonomics over SignalR vs. HTTP SSE.
  • Whether [AgentTool] schemas should reuse the JSON-schema generation planned/used elsewhere rather than a new generator.

Filed as part of a broader AI-capability planning round; happy to split into smaller issues if the shape survives discussion.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions