.NET API
IToolApprovalPresenter
Tracon.Abstractions.dllResolves a human-readable presentation for a tool call that is about to publish an
approval request — turning, for example, { "orderId": "ORD-1001" } into
“Cancel order for Priya Shah”.
public interface IToolApprovalPresenterExamples
Section titled “Examples”public sealed class OrderApprovalPresenter(IServiceScopeFactory scopes) : IToolApprovalPresenter{ public async ValueTask<ToolApprovalPresentation?> PresentAsync( ToolApprovalContext context, CancellationToken cancellationToken = default) { if (context.GetString("orderId") is not { } orderId) { return null; }
using var scope = scopes.CreateScope(); var orders = scope.ServiceProvider.GetRequiredService<IOrderRepository>(); var customerName = await orders.GetAsync(orderId);
return new ToolApprovalPresentation { EntityType = "order", EntityId = orderId, EntityName = $"Order {orderId}", Message = $"Cancel order {orderId} for {customerName}.", }; }}Remarks
Section titled “Remarks”Read-only and best-effort. This is not an authorization boundary — IToolAuthorizationHandler and IToolArgumentsValidator are the gates, and both fail closed. A presenter fails open: registered or not, resolving or not, timing out or throwing, the approval request is published either way. A presentation error must never suppress a request that needs a decision. The raw arguments (PendingApproval.Arguments) are always available beside whatever this method returns, so an operator can still decide even when it returns null.
Register it as a singleton and resolve scoped dependencies through
IServiceScopeFactory. This method runs on the tool-call path, where
Microsoft Agent Framework hands every tool an empty service provider
(AIFunctionArguments.Services resolves nothing — see the framework notes on
IToolAuthorizationHandler). The same limit applies here: a scoped dependency,
such as a DbContext, must be resolved through an injected
IServiceScopeFactory, not a constructor parameter.
Tenant behavior — EXPECTED tenant. The tenant is carried by
ToolApprovalContext.TenantId, the same way the code-defined approval
policy callback (ITraconBuilder.AddToolApprovalPolicy) reads it — never the
ambient tenant, since a presenter’s own scoped lookup must never leak another tenant’s
entity name into this one’s approval card.
Methods
Section titled “Methods”PresentAsync(ToolApprovalContext, CancellationToken)
Section titled “ PresentAsync(ToolApprovalContext, CancellationToken)”Resolves a presentation for one pending tool call.
ValueTask<ToolApprovalPresentation?> PresentAsync(ToolApprovalContext context, CancellationToken cancellationToken = default)Parameters
Section titled “Parameters”context ToolApprovalContext
The tool call the approval request was raised for.
cancellationToken CancellationToken
The cancellation token.
Returns
Section titled “Returns”ValueTask<ToolApprovalPresentation?>
The presentation, or null when nothing could be resolved. A
thrown exception or a call that runs past the configured timeout
(TraconToolOptions.ApprovalPresentationTimeout) is treated the same way.