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:
- Register a document and receive an opaque document id.
- Expose OfficeAgent.NET operations as AI functions.
- Add those functions to the existing IChatClient.
- Capture the output document id returned by apply_plan.
- 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
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();
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();
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);
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);
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)