Skip to content

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 implements ITool, 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 a maxItems parameter.

  • File paths failing? Check sandbox rules / allowed roots; normalize and reject .. traversal.