Using Tools in Assistant Engine¶
This page is a developer-focused guide to Assistant Engine’s Tooling—the feature that lets your AI do things inside your app, not just talk about them. Thanks to .NET’s first-class dependency injection and Assistant Engine’s discovery pipeline, adding new capabilities is fast, safe, and genuinely fun to extend. Assistant Engine builds on Microsoft.Extensions.AI so your tools are natively understood by modern .NET chat clients and function-calling models.
Why this is awesome
One class. One interface. Done.
Drop a class into Assistant Engine.Services.Implementation.Tools
, implement ITool
, and Assistant Engine auto-discovers it. Your methods (with descriptions and typed parameters) instantly become callable tools the model can invoke—with your app’s full DI context (DBs, logging, config, anything in your container).
What is a “Tool”?¶
A Tool is a set of strongly-typed actions the model can invoke at runtime—anything from “ExecuteSQL()” and “GetTableSchema()” to “ReadFile()” or “PurgeCache()”. Each public method you expose:
- Has a clear [Description] so the model knows when to use it.
- Accepts typed parameters (also described) the model can fill in.
- Runs with your DI-injected services, so it executes with real context.
- Returns simple results (strings / DTOs / enumerables) the model can reason about.
Assistant Engine forwards your method and parameter descriptions to Microsoft.Extensions.AI, which turns them into a structured function/tool schema for the model.
Model-guided execution
The Assistant model decides when to call tools and with what parameters. You keep execution control (authorization, validation, rate limits), while Assistant Engine handles discovery, schema, and invocation.
Quick Start: Author a Tool¶
Put a class in the Assistant Engine.Services.Implementation.Tools
namespace and implement ITool
(marker interface). Inject anything you need via the constructor.
using System.ComponentModel; // for [Description]
using System.Security; // for SecurityElement.Escape
using Assistant Engine.Services.Abstractions; // where ITool lives (marker)
using Microsoft.Extensions.Logging;
namespace Assistant Engine.Services.Implementation.Tools
{
/// <summary>
/// File system utilities for listing, reading, and writing files.
/// </summary>
public class FileSystemTool : ITool
{
private readonly ILogger<FileSystemTool> _logger;
public FileSystemTool(ILogger<FileSystemTool> logger)
{
_logger = logger;
}
[Description("Reads entire file contents as text.")]
public async Task<string> ReadFileAsync(
[Description("Path to the file.")] string filePath,
CancellationToken ct = default)
{
try
{
return await File.ReadAllTextAsync(filePath, ct);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "ReadFileAsync failed for {Path}", filePath);
return $"<error message=\"{SecurityElement.Escape(ex.Message)}\" type=\"{ex.GetType().Name}\" />";
}
}
[Description("Writes text to a file (creates or overwrites).")]
public async Task<string> WriteFileAsync(
[Description("Path to create/overwrite.")] string filePath,
[Description("Text content to write.")] string content,
CancellationToken ct = default)
{
try
{
await File.WriteAllTextAsync(filePath, content, ct);
return "ok";
}
catch (Exception ex)
{
_logger.LogError(ex, "WriteFileAsync failed for {Path}", filePath);
return $"<error message=\"{SecurityElement.Escape(ex.Message)}\" type=\"{ex.GetType().Name}\" />";
}
}
}
}
Parameter & method docs matter
Models choose tools by your [Description] text. Be explicit about what it does, inputs, units, constraints, and danger zones (e.g., “paths are sandboxed under C:\Data
”).
How Assistant Engine Wires It Up¶
Assistant Engine auto-discovers classes implementing ITool
under Assistant Engine.Services.Implementation.Tools
and registers them with DI. At runtime, Assistant Engine exposes each method (and parameter descriptions) to the chat client so the model can call them.
- DI first: any constructor parameters get resolved (DbContexts, HttpClient, caches, etc.).
- Schema generation:
[Description]
on methods & parameters become the tool and arg docs. - Invocation: the model sends a tool call; Assistant Engine binds args → calls your method → returns results.
No boilerplate needed! You don’t need to hand-roll function schemas. Assistant Engine integrates with Microsoft.Extensions.AI so tools are first-class in the chat pipeline.
Best Practices¶
-
Keep methods small & single-purpose One operation per method (e.g.,
ListDirectory
,ReadFile
,WriteFile
). The model composes them. -
Use typed parameters Prefer
int
,bool
,DateTime
, enums, and structured DTOs. Add[Description]
to each parameter. -
Return model-friendly shapes
string
,IEnumerable<string>
, or lightweight DTOs. Avoid huge payloads; paginate or cap counts. -
Defensive I/O and security Validate paths, whitelist roots, and sanitize errors. Consider a “tools” config for allowed roots.
-
Logging Log warnings for expected user mistakes; errors for system failures. Don’t leak secrets in messages.
-
CancellationToken Accept
CancellationToken
to keep tool calls responsive under streaming/abort scenarios.
Troubleshooting¶
-
Tool not showing up? Confirm namespace is
Assistant Engine.Services.Implementation.Tools
, class implementsITool
, and it’s public. -
Model keeps calling the wrong tool? Tighten your
[Description]
text. State clear preconditions and what it returns. -
Large outputs get truncated? Page your results (
take
/skip
) and offer amaxItems
parameter. -
File paths failing? Check sandbox rules / allowed roots; normalize and reject
..
traversal.