Skip to content

Latest commit

 

History

History
66 lines (43 loc) · 4.03 KB

File metadata and controls

66 lines (43 loc) · 4.03 KB

In-Function-Loop Checkpointing

This sample demonstrates how ChatClientAgent can persist chat history after each individual call to the AI service using the RequirePerServiceCallChatHistoryPersistence option. This per-service-call persistence ensures intermediate progress is saved during the function invocation loop.

What This Sample Shows

When an agent uses tools, the FunctionInvokingChatClient loops multiple times (service call → tool execution → service call → …). By enabling RequirePerServiceCallChatHistoryPersistence = true, chat history is persisted after each service call via the PerServiceCallChatHistoryPersistingChatClient decorator:

  • A PerServiceCallChatHistoryPersistingChatClient decorator is inserted into the chat client pipeline
  • Before each service call, the decorator loads history from the ChatHistoryProvider and prepends it to the request
  • After each service call, the decorator notifies the ChatHistoryProvider (and any AIContextProvider instances) with the new messages
  • Only new messages are sent to providers on each notification — messages that were already persisted in an earlier call within the same run are deduplicated automatically

By default (without RequirePerServiceCallChatHistoryPersistence), chat history is persisted at the end of the full agent run instead. To use per-service-call persistence, set RequirePerServiceCallChatHistoryPersistence = true on ChatClientAgentOptions.

With RequirePerServiceCallChatHistoryPersistence = true, the behavior matches that of chat history stored in the underlying AI service exactly.

Per-service-call persistence is useful for:

  • Crash recovery — if the process is interrupted mid-loop, the intermediate tool calls and results are already persisted
  • Observability — you can inspect the chat history while the agent is still running (e.g., during streaming)
  • Long-running tool loops — agents with many sequential tool calls benefit from incremental persistence

How It Works

The sample asks the agent about the weather and time in three cities. The model calls the GetWeather and GetTime tools for each city, resulting in multiple service calls within a single RunStreamingAsync invocation. After the run completes, the sample prints the full chat history to show all the intermediate messages that were persisted along the way.

Pipeline Architecture

ChatClientAgent
  └─ FunctionInvokingChatClient    (handles tool call loop)
       └─ PerServiceCallChatHistoryPersistingChatClient  (persists after each service call)
            └─ Leaf IChatClient            (Azure OpenAI)

Prerequisites

  • .NET 10 SDK or later
  • Azure OpenAI service endpoint and model deployment
  • Azure CLI installed and authenticated

Note: This sample uses DefaultAzureCredential. Sign in with az login before running. For production, prefer a specific credential such as ManagedIdentityCredential. For more information, see the Azure CLI authentication documentation.

Environment Variables

$env:AZURE_OPENAI_ENDPOINT="https://your-resource.openai.azure.com/"  # Required
$env:AZURE_OPENAI_DEPLOYMENT_NAME="gpt-5.4-mini"                      # Optional, defaults to gpt-5.4-mini

Running the Sample

cd dotnet/samples/02-agents/Agents/Agent_Step19_InFunctionLoopCheckpointing
dotnet run

Expected Behavior

The sample runs two conversation turns:

  1. First turn — asks about weather and time in three cities. The model calls GetWeather and GetTime tools (potentially in parallel or sequentially), then provides a summary. The chat history dump after the run shows all the intermediate tool call and result messages.

  2. Second turn — asks a follow-up question ("Which city is the warmest?") that uses the persisted conversation context. The chat history dump shows the full accumulated conversation.

The chat history printout uses session.TryGetInMemoryChatHistory() to inspect the in-memory storage.