Skip to content

pinkroosterai/EventEmittingFunctionInvokingChatClient

Repository files navigation

PinkRooster.EventEmittingFunctionInvokingChatClient

A FunctionInvokingChatClient subclass that emits async events before and after each tool invocation, giving you full observability into the Microsoft.Extensions.AI function-calling pipeline.

Installation

dotnet add package PinkRooster.EventEmittingFunctionInvokingChatClient

Quick Start

using Microsoft.Extensions.AI;

// Build a pipeline with event-emitting function invocation
var pipeline = new ChatClientBuilder(innerClient)
    .Use(client =>
    {
        var funcClient = new EventEmittingFunctionInvokingChatClient(client);

        funcClient.ToolCallStarting += async (sender, e) =>
        {
            Console.WriteLine($"Starting: {e.FunctionName} [{e.CallId}]");
            await Task.CompletedTask;
        };

        funcClient.ToolCallCompleted += async (sender, e) =>
        {
            var icon = e.Succeeded ? "OK" : "FAIL";
            Console.WriteLine($"{icon}: {e.FunctionName} in {e.Duration.TotalMilliseconds:F0}ms");
            await Task.CompletedTask;
        };

        return funcClient;
    })
    .Build();

Features

  • ToolCallStarting event fires before each function invocation with function name, arguments, call ID, and iteration info
  • ToolCallCompleted event fires after each invocation with result/exception, wall-clock duration, and termination status
  • Accurate timing that measures only function execution, excluding event handler overhead
  • Thread-safe: works correctly with AllowConcurrentInvocation = true
  • Robust error handling in the completed event (handler exceptions never swallow function exceptions)
  • Overridable OnCompletedHandlerException for custom error handling in completed event handlers

Event Args

ToolCallStartingEventArgs

Property Type Description
FunctionName string Name of the function about to be invoked
CallId string Unique identifier for this tool call
Arguments AIFunctionArguments? Arguments passed to the function
Iteration int 0-based roundtrip iteration number
FunctionCallIndex int 0-based index within the current iteration
FunctionCount int Total function calls in the current iteration
IsStreaming bool Whether this is inside a streaming response
Context FunctionInvocationContext Full context for advanced scenarios

ToolCallCompletedEventArgs

Property Type Description
FunctionName string Name of the function that was invoked
CallId string Unique identifier for this tool call
Result object? Return value, or null on failure
Exception Exception? Exception thrown, or null on success
Duration TimeSpan Wall-clock duration (excluding handler time)
Succeeded bool Convenience: true when Exception is null
TerminationRequested bool Whether the function requested loop termination
Context FunctionInvocationContext Full context for advanced scenarios

Example

See the Tavily Research Agent for a full working example that uses this library with the Tavily MCP server to build an interactive research assistant.

License

MIT

About

A FunctionInvokingChatClient subclass that emits async events before and after each tool invocation for Microsoft.Extensions.AI

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages