DEV Community

Cover image for Add Word-Editing Tools to a .NET IChatClient with OfficeAgent.NET
Ilia Sokolov
Ilia Sokolov

Posted on • Edited on

Add Word-Editing Tools to a .NET IChatClient with OfficeAgent.NET

Most AI demos end with text in a chat window. Business workflows often need something more concrete: a Word document that a person can open, review, and approve.

If your .NET application already uses Microsoft.Extensions.AI.IChatClient, you do not need to adopt a full agent framework to add that capability. OfficeAgent.NET can expose bounded Word-editing operations directly as AIFunction tools.

The integration has a clear boundary:

  • IChatClient manages the conversation and function-calling loop.
  • OfficeAgent.NET inspects, plans, previews, and applies Word changes.
  • Your application controls document storage and delivery.

The document bytes stay outside the model context.

The workflow

The host performs five steps:

  1. Register a document and receive an opaque document id.
  2. Expose OfficeAgent.NET operations as AI functions.
  3. Add those functions to the existing IChatClient.
  4. Capture the output document id returned by apply_plan.
  5. Retrieve the finished .docx through the configured document provider.

The complete sample makes one tracked edit: it changes 60 days to 30 days without modifying anything else.

1. Register the document and create the tools

Install the OfficeAgent.NET packages:

dotnet add package OfficeAgent.Core --version 0.2.1
dotnet add package OfficeAgent.Word --version 0.2.1
dotnet add package OfficeAgent.AgentFramework --version 0.2.1
Enter fullscreen mode Exit fullscreen mode

Then configure Word support and register the source document:

using ServiceProvider services = new ServiceCollection()
    .AddWordFormat()
    .AddFileSystemDocumentProvider("contracts", storageRoot)
    .AddOfficeAgent()
    .BuildServiceProvider();

OfficeAgentClient office =
    services.GetRequiredService<OfficeAgentClient>();

DocumentReference source = await office.RegisterAsync(
    "contracts",
    Path.Combine(storageRoot, "contract.docx"));

AIFunction[] tools = new OfficeAgentTools(office).AsAIFunctions();
Enter fullscreen mode Exit fullscreen mode

Despite the package name, this path does not use ChatClientAgent.
AsAIFunctions() returns ordinary functions that can be attached to an IChatClient.

2. Add function execution to IChatClient

Create the Azure OpenAI client, convert it to IChatClient, and add function invocation:

IChatClient chat = new AzureOpenAIClient(
        new Uri(endpoint),
        new DefaultAzureCredential())
    .GetChatClient(deployment)
    .AsIChatClient()
    .AsBuilder()
    .UseFunctionInvocation()
    .Build();
Enter fullscreen mode Exit fullscreen mode

UseFunctionInvocation() runs the tool calls requested by the model, returns their structured results, and continues until the model produces its final response.

In a production host, add a request-scoped function invoker that records tool calls and captures outputDocumentId from a successful apply_plan result. Do not rely on the model to repeat that id in its prose, and do not store request state in a shared singleton closure.

The runnable sample includes result normalization because function adapters can surface the same JSON result as either an object or a JSON string. Handling both forms makes output capture reliable.

3. Give the model a bounded editing request

Provide the registered document id, OfficeAgent guidance, and a narrow instruction:

var messages = new List<ChatMessage>
{
    new(
        ChatRole.System,
        $"""
        You are editing connectionId=contracts,
        documentId={source.ItemId}.

        {OfficeAgentTools.SystemPromptGuidance}

        Inspect before planning. Preview before applying.
        When applying, use saveMode NewVersion.
        """),
    new(
        ChatRole.User,
        "Change '60 days' to '30 days' as a tracked change. " +
        "Make no other edits.")
};

var options = new ChatOptions
{
    Tools = tools.Cast<AITool>().ToList(),
    AllowMultipleToolCalls = false,
    MaxOutputTokens = 1200
};

ChatResponse response =
    await chat.GetResponseAsync(messages, options);
Enter fullscreen mode Exit fullscreen mode

The safety sequence is discovery, preview, then apply. OfficeAgent.NET validates the edit plan before changing the document, while the host retains control of which document is registered and where the result is stored.

4. Retrieve the edited Word document

After apply_plan commits successfully, retrieve the document using the output id captured by the host:

using var saved = await office.OpenReadAsync(
    DocumentReference.ForFileSystem(
        "contracts",
        outputDocumentId));

await using var output =
    File.Create("reviewed-contract.docx");

await saved.Stream.CopyToAsync(output);
Enter fullscreen mode Exit fullscreen mode

The model never needs the .docx bytes. Your application can return the file through its normal download, attachment, SharePoint, or storage workflow.

Try the complete sample

The article excerpts focus on the integration boundary. The
complete runnable sample contains the full host, package references, Azure configuration, JSON result normalization, synthetic fixture, logging, and output checks.

Start with a synthetic document, keep the first run single-request, and confirm that the trace ends with apply_plan.

OfficeAgent.NET gives an existing .NET chat application a focused way to produce reviewable Word documents without moving file content through the model or replacing the application's current AI architecture.

Top comments (0)