Adding a tool
An agent without tools can only talk. A tool is a method in your codebase that the model may call.
Register one
Section titled “Register one”Mark the method and let the source generator find it:
using AgentPrism;
internal static class OrderTools{ /// <summary>Returns the shipping status of an order.</summary> /// <param name="orderId">The order number.</param> [AgentPrismTool("get_order_status", "Returns the shipping status of an order.")] public static string GetOrderStatus(string orderId) => $"Order {orderId} has shipped. Estimated delivery: 2 days.";}builder.AddAgentPrism() .AddGeneratedTools();AddGeneratedTools() is filled in at compile time — no reflection, no trimming or
AOT warning. A method without the attribute is not a tool, so adding a helper to the
class does not quietly expose it to a model.
Then name it on the agent:
agentPrism.AddAgent(new AgentDefinition{ Name = "support", // … ToolNames = ["get_order_status"],});An unknown tool name fails definition compilation, not C# compilation. A database definition is rejected when you validate or save it. A code definition is compiled when the catalog first resolves it and does not resolve until the registration is fixed. In either case, the model never receives a tool name AgentPrism cannot bind.
The other two ways
Section titled “The other two ways”.AddTool(GetOrderStatus) // from a delegate — uses reflection.AddToolsFrom<OrderTools>() // scans a type — uses reflectionBoth work and both carry [RequiresUnreferencedCode] and [RequiresDynamicCode].
The warning is handed to you rather than suppressed. Use AddGeneratedTools() unless
your tools live in an assembly you do not compile.
The rule that trips people up
Section titled “The rule that trips people up”Tools that need a human
Section titled “Tools that need a human”Some tools should not run unattended:
[AgentPrismTool("issue_refund", "Refunds an order.", RequiresApproval = true)]public static string IssueRefund(string orderId) => /* … */;
// or, for a tool registered from a delegate:agentPrism.AddTool(IssueRefund, requiresApproval: true);The tool is wrapped in the registry — the single place where “an agent may only point
at a registered tool” is enforced, so there is no code path that skips the wrapper.
When the model calls it, the run pauses and an approval request appears in the
console. What happens next depends on how the run was started: a streaming run
carries the approval in its next turn, while a queued run stops at
AwaitingApproval and waits in the approval mailbox.
Standing decisions are possible too — an approval rule pre-approves a tool, or one exact set of arguments, so it stops asking. Those rules are visible and revocable under Governance.
Try it
Section titled “Try it”curl -N -X POST http://localhost:5081/agentprism/api/agents/support/run \ -H 'Content-Type: application/json' \ -d '{"message":"Where is order 4182?"}'The stream carries ToolInvoking and ToolInvoked events around the model’s reply,
and each call is written to the run with its arguments, its result, its duration, and
its error if it had one.
Read next
Section titled “Read next”- Persistence — keep the history
- Tools, skills, and MCP — the whole picture, including the two exceptions to “code only”