Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Cold-start latency is the time a hosted agent in Microsoft Foundry spends preparing a new sandbox before it can process requests. Importing dependencies and creating the initial application state add to this delay.
Memory snapshots capture the application's initialized state so new sandboxes can restore it instead of repeating reusable startup work. They can reduce startup latency, but don't remove request-time work, such as model inference or remote tool calls.
Important
Use memory snapshots only if your agent doesn't need $HOME to persist. Snapshot-enabled sessions currently don't preserve $HOME, other local files, or process memory across idle suspension and resumption. If your agent relies on files in $HOME surviving that cycle, don't enable memory snapshots.
This article explains how snapshots work, shows code examples with and without lifecycle hooks, and shows how to enable snapshots and check latency and restore behavior.
Prerequisites
- A hosted agent project that meets the runtime contract and the deployment and permission requirements in Deploy a hosted agent.
- An agent that doesn't need
$HOMEor other local files to persist across idle suspension and resumption. For details, see Check session-state requirements. - A snapshot-capable Agent Server package for your agent's language. Packages are available for Python and .NET; to see versions, select Python or C# at the top of this article.
Understand how snapshots reduce startup work
Without snapshots, each new sandbox repeats your application's startup initialization before it can handle requests. This cost isn't repeated for every request to an already-running sandbox.
Memory snapshots move reusable initialization into agent-version preparation. Foundry captures the initialized process as a shared startup baseline, then restores that baseline for new session sandboxes.
For example, suppose loading fixed reference data takes three seconds at startup. Without snapshots, each new sandbox repeats that work. With snapshots, the data loads during version preparation and restored sandboxes reuse it.
The three seconds are illustrative, not a measured performance guarantee. Sessions still incur restore and session-specific setup costs.
The capture-and-restore lifecycle has the following phases:
| Phase | What happens |
|---|---|
| Initialization | Foundry starts a temporary instance of your agent and waits for its readiness probe to succeed. |
| Capture | Foundry runs your before-snapshot hook, if registered, then captures the initialized process. |
| Session startup | Foundry restores an isolated sandbox from the version's baseline. |
| Restore initialization | The SDK applies session environment overrides, then runs your after-restore hook, if registered, before Foundry forwards requests. |
| Request handling | Your agent handles requests using the prepared application state and current session configuration. |
Session environment overrides are environment values that differ for a session from the captured process, such as credentials that can change between sessions. For how to configure environment values and connection-based secrets, see Configure environment variables for a hosted agent.
Changes to an agent's image or definition require a new version with its own snapshot preparation. When you delete a version, Foundry initiates cleanup of its associated snapshot; you don't manage that snapshot separately.
Check session-state requirements
Before you enable snapshots, check where your agent stores session state. A memory snapshot is a prepared starting point, not a checkpoint of an ongoing session. After idle suspension, Foundry restores the version's startup baseline rather than the session's latest process state.
Snapshot-enabled sessions don't preserve changes to process memory or local files, including $HOME, across this idle-and-resume cycle. A conversation cached only in a variable or a file written during a turn isn't available on resumption. Store state that must survive externally and reload it when needed.
This behavior differs from the persistent session filesystem described for ordinary hosted agents in Manage hosted agent sessions. If your agent depends on that persistence, don't enable memory snapshots. Lifecycle hooks don't change this persistence behavior.
Platform-managed Responses conversation history is separate from container memory; restoring the process doesn't restore arbitrary application objects. With the Invocations protocol, your application manages its own conversation and application state.
Choose whether your application needs lifecycle hooks
Lifecycle hooks are optional functions that run at the snapshot boundary. The SDK handles the POST /_before_snapshot and POST /_after_restore platform endpoints and runs your hooks when you register them. You don't call these endpoints yourself.
If your application finishes reusable initialization before reporting ready and has no live resources to rebuild, you don't need lifecycle hooks. Install a snapshot-capable SDK and enable snapshots.
If your application owns live resources, such as a database connection, register a before-snapshot hook to release them and an after-restore hook to reconnect. When you write hooks:
- Keep before-snapshot cleanup focused on application resources; don't stop the process or HTTP server.
- Keep after-restore work small. Reloading immutable data there puts its cost back on every session start.
- Rebuild a client after restore only when it holds a live connection or caches values that can change, such as credentials. Updating an environment variable alone doesn't update a client that cached its old value.
- Make external side effects safe to retry. The SDK serializes lifecycle calls and skips a restore identifier that already completed, but a new restore identifier runs the after-restore hook again, even for the same session.
The examples later in this article show both approaches.
Install snapshot-capable packages
To try memory snapshots with an existing agent, start with a Python Responses sample or a Python Invocations sample. For a guided setup with the Azure Developer CLI (azd), see Create and deploy a hosted agent.
Use the following released package versions. Install the Core package and only the protocol package that your agent uses.
| Package | Version | Used by |
|---|---|---|
azure-ai-agentserver-core |
2.3.0 |
Both protocols. |
azure-ai-agentserver-responses |
2.4.0 |
Responses agents. |
azure-ai-agentserver-invocations |
1.3.0 |
Invocations agents, including both examples in this article. |
If you start from a linked sample, it might pin older versions. Update the sample's dependency inputs to these versions, regenerate its lockfile and requirements.txt as applicable, and reinstall dependencies before testing. For example, install the Invocations packages with:
python -m pip install \
azure-ai-agentserver-core==2.3.0 \
azure-ai-agentserver-invocations==1.3.0
For a Responses agent, replace azure-ai-agentserver-invocations==1.3.0 with azure-ai-agentserver-responses==2.4.0.
Reference: SDK snapshot lifecycle documentation.
Installing these packages doesn't enable snapshots by itself; also enable snapshots on the agent version.
Do reusable work at startup
Start with work that produces the same result for every session of an agent version. Import dependencies and load immutable data before your agent reports ready. Foundry can capture the result instead of making each restored sandbox repeat the initialization.
For example, loading a large, fixed reference dataset or initializing reusable parts of a third-party client can add time to every cold startup. Complete that work before capture so new sessions can reuse the prepared state.
In a Python Agent Server application, finish synchronous initialization before calling app.run(). The server doesn't listen until you start it, on port 8088 by default. The /readiness endpoint can't return success before the preceding initialization finishes, so this pattern needs no additional readiness gate.
Initialization must complete within the platform's startup readiness budget. If you start the server while initialization continues in background tasks, register a custom @app.readiness_handler that returns 503 until that work completes. The default readiness response is 200 OK; it doesn't track background initialization. See Health probe.
Only put shared, version-wide data in the startup state. Load a user's conversation or private documents when handling that user's session, not during shared startup. If shared data, such as a tool catalog, can change without a new agent version, refresh it according to an explicit policy.
Example without lifecycle hooks
This complete Python example downloads fixed reference data before starting the server and answers requests from memory. It doesn't keep a live connection or session-specific state, so it doesn't need lifecycle hooks.
Install the Invocations packages listed in Install snapshot-capable packages and httpx. Set REFERENCE_DATA_URL to a trusted HTTPS URL for versioned, non-sensitive JSON, readable without authentication. For example, the file can contain {"reset-device": "Press and hold the reset button."}.
Save the following code as main.py:
import os
import httpx
from azure.ai.agentserver.invocations import InvocationAgentServerHost
from starlette.responses import JSONResponse
app = InvocationAgentServerHost()
def load_reference_data(url):
"""Load shared, immutable data before snapshot capture."""
with httpx.Client(timeout=30.0) as client:
response = client.get(url)
response.raise_for_status()
data = response.json()
if not isinstance(data, dict):
raise ValueError("Reference data must be a JSON object.")
return data
@app.invoke_handler
async def handle(request):
body = await request.json()
return JSONResponse({"answer": REFERENCE_DATA[body["topic"]]})
REFERENCE_DATA = load_reference_data(os.environ["REFERENCE_DATA_URL"])
app.run()
Reference: Python Agent Server host and handlers.
Send {"topic": "reset-device"} to receive {"answer": "Press and hold the reset button."} with the example reference data. The handler assumes the requested topic exists.
The download and parsing finish before app.run(). The HTTP client closes immediately after loading; only the reusable data remains for capture. Restored sessions reuse that data without downloading it again. A failed download or invalid JSON fails startup instead of reporting readiness with missing data.
The latency benefit depends on how much startup work your application can reuse.
Example with lifecycle hooks
Use this alternative main.py when request handling also needs a live PostgreSQL connection. It keeps the same startup cache and registers both lifecycle hooks: the before-snapshot hook closes any existing database connection, and the after-restore hook opens a fresh one.
In addition to the previous example's dependencies, install Psycopg 3 (psycopg[binary]). You need a reachable PostgreSQL server and a database role that can connect. Configure:
REFERENCE_DATA_URL: The same versioned reference-data URL as in the previous example.DB_HOSTandDB_NAME: The PostgreSQL hostname and database name.DB_SSLROOTCERT: The path to the trusted CA certificate file for the database server.DB_USERandDB_PASSWORD: Credentials supplied through session environment overrides, not embedded in the shared startup data.
import os
import httpx
import psycopg
from azure.ai.agentserver.core import AgentSessionContext
from azure.ai.agentserver.invocations import InvocationAgentServerHost
from starlette.responses import JSONResponse
app = InvocationAgentServerHost()
database: psycopg.AsyncConnection | None = None
def load_reference_data(url):
"""Load shared, immutable data before snapshot capture."""
with httpx.Client(timeout=30.0) as client:
response = client.get(url)
response.raise_for_status()
data = response.json()
if not isinstance(data, dict):
raise ValueError("Reference data must be a JSON object.")
return data
def initialize():
"""Prepare reusable state before the server reports ready."""
global REFERENCE_DATA
REFERENCE_DATA = load_reference_data(os.environ["REFERENCE_DATA_URL"])
async def close_database():
"""Release the live connection without discarding cached data."""
global database
if database is not None:
await database.close()
database = None
@app.before_snapshot_handler
async def before_snapshot():
"""Keep live database connections out of the captured state."""
await close_database()
@app.after_restore_handler
async def after_restore(_context: AgentSessionContext):
"""Reconnect with session credentials; don't reload shared data."""
global database
await close_database()
database = await psycopg.AsyncConnection.connect(
host=os.environ["DB_HOST"],
dbname=os.environ["DB_NAME"],
user=os.environ["DB_USER"],
password=os.environ["DB_PASSWORD"],
sslmode="verify-full",
sslrootcert=os.environ["DB_SSLROOTCERT"],
connect_timeout=10,
autocommit=True,
)
@app.invoke_handler
async def handle(request):
"""Use restored reference data and the fresh database connection."""
body = await request.json()
topic = body["topic"]
async with database.cursor() as cursor:
await cursor.execute("SELECT current_user")
row = await cursor.fetchone()
return JSONResponse(
{"answer": REFERENCE_DATA[topic], "database_user": row[0]}
)
@app.shutdown_handler
async def shutdown():
"""Release the connection when the restored process exits."""
await close_database()
initialize()
app.run()
Reference: Python snapshot lifecycle handlers.
The initialize() function prepares the same reusable data before app.run(). No database connection opens during shared preparation, so the captured state contains the cached data but no live connection.
The before-snapshot hook closes the connection if one exists; it's safe when database is already None. The shutdown handler uses the same cleanup.
Before the after-restore hook runs, the SDK applies session environment overrides to os.environ. The hook reads the current credentials and connects to PostgreSQL without reloading reference data. It first closes any previous connection so another restore cycle doesn't retain it.
Missing credentials or a failed connection cause the hook to fail. Foundry doesn't forward requests until the after-restore hook succeeds.
Send {"topic": "reset-device"} to get the cached answer and the connected PostgreSQL role from SELECT current_user. No application table is required. The handler assumes the topic exists. A database role isn't the identity of the caller making the request.
Install snapshot-capable packages
Use the following prerelease NuGet package versions. Install the Core package and only the protocol package that your agent uses.
| Package | Version | Used by |
|---|---|---|
Azure.AI.AgentServer.Core |
1.0.0-beta.30 |
Both protocols. |
Azure.AI.AgentServer.Responses |
1.0.0-beta.9 |
Responses agents. |
Azure.AI.AgentServer.Invocations |
1.0.0-beta.7 |
Invocations agents, including both examples in this article. |
For example, create a console project and add the Invocations packages:
dotnet new console -n SnapshotAgent
cd SnapshotAgent
dotnet add package Azure.AI.AgentServer.Core --version 1.0.0-beta.30
dotnet add package Azure.AI.AgentServer.Invocations --version 1.0.0-beta.7
For a Responses agent, add Azure.AI.AgentServer.Responses version 1.0.0-beta.9 instead of the Invocations package.
If your project targets .NET 8, also add Microsoft.Extensions.Logging version 10.0.10. Without it, the agent fails at startup because it can't load Microsoft.Extensions.Logging.
dotnet add package Microsoft.Extensions.Logging --version 10.0.10
Reference: .NET snapshot lifecycle guidance.
Installing these packages doesn't enable snapshots by itself; also enable snapshots on the agent version.
Do reusable work at startup
Start with work that produces the same result for every session of an agent version. Load dependencies and immutable data before your agent reports ready. Foundry can capture the result instead of making each restored sandbox repeat the initialization.
For example, loading a large, fixed reference dataset or initializing reusable parts of a third-party client can add time to every cold startup. Complete that work before capture so new sessions can reuse the prepared state.
In a .NET Agent Server application, finish initialization before calling InvocationsServer.Run. The server doesn't listen until Run starts it, on port 8088 by default. The /readiness endpoint can't return success before the preceding initialization finishes, so this pattern needs no additional readiness gate.
Initialization must complete within the platform's startup readiness budget. If you start the server while initialization continues in the background, add an application health check with ConfigureHealth that reports unhealthy until that work completes. See Health endpoint.
Only put shared, version-wide data in the startup state. Load a user's conversation or private documents when handling that user's session, not during shared startup. If shared data, such as a tool catalog, can change without a new agent version, refresh it according to an explicit policy.
Example without lifecycle hooks
This complete C# example downloads fixed reference data before starting the server and answers requests from memory. It doesn't keep a live connection or session-specific state, so it doesn't need lifecycle hooks.
Add the packages listed in Install snapshot-capable packages. Set REFERENCE_DATA_URL to a trusted HTTPS URL for versioned, non-sensitive JSON, readable without authentication. For example, the file can contain {"reset-device": "Press and hold the reset button."}.
Replace the contents of Program.cs with the following code:
using System.Net.Http.Json;
using System.Text.Json;
using Azure.AI.AgentServer.Invocations;
using Microsoft.AspNetCore.Http;
var referenceData = await LoadReferenceDataAsync(
Environment.GetEnvironmentVariable("REFERENCE_DATA_URL")
?? throw new InvalidOperationException("Set REFERENCE_DATA_URL."));
InvocationsServer.Run(_ => new TopicHandler(referenceData), args);
// Load shared, immutable data before snapshot capture.
static async Task<IReadOnlyDictionary<string, string>> LoadReferenceDataAsync(
string url)
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
return await client.GetFromJsonAsync<Dictionary<string, string>>(url)
?? throw new InvalidOperationException(
"Reference data must be a JSON object.");
}
public sealed record TopicRequest(string Topic);
public sealed class TopicHandler(
IReadOnlyDictionary<string, string> referenceData) : InvocationHandler
{
private static readonly JsonSerializerOptions JsonOptions =
new(JsonSerializerDefaults.Web);
public override async Task HandleAsync(
HttpRequest request,
HttpResponse response,
InvocationContext context,
CancellationToken cancellationToken)
{
var body = await JsonSerializer.DeserializeAsync<TopicRequest>(
request.Body, JsonOptions, cancellationToken);
await response.WriteAsJsonAsync(
new { answer = referenceData[body!.Topic] }, cancellationToken);
}
}
Reference: InvocationsServer and InvocationHandler.
Send {"topic": "reset-device"} to receive {"answer":"Press and hold the reset button."} with the example reference data. The handler assumes the requested topic exists.
The download and parsing finish before InvocationsServer.Run. The HttpClient is disposed immediately after loading; only the reusable data remains for capture. Restored sessions reuse that data without downloading it again. A failed download or JSON that isn't an object of strings fails startup instead of reporting readiness with missing data.
The latency benefit depends on how much startup work your application can reuse.
Example with lifecycle hooks
Use this alternative Program.cs when request handling also needs a live PostgreSQL connection. It keeps the same startup cache and adds a DatabaseConnection class that implements IAgentSnapshotLifecycle: BeforeSnapshotAsync closes any existing database connection, and AfterRestoreAsync opens a fresh one. The lifecycle API is experimental, so the file suppresses diagnostic AAAS002.
In addition to the previous example's packages, add Npgsql. You need a reachable PostgreSQL server and a database role that can connect.
dotnet add package Npgsql
Configure:
REFERENCE_DATA_URL: The same versioned reference-data URL as in the previous example.DB_HOSTandDB_NAME: The PostgreSQL hostname and database name.DB_SSLROOTCERT: The path to the trusted CA certificate file for the database server.DB_USERandDB_PASSWORD: Credentials supplied through session environment overrides, not embedded in the shared startup data.
#pragma warning disable AAAS002
using System.Net.Http.Json;
using System.Text.Json;
using Azure.AI.AgentServer.Core;
using Azure.AI.AgentServer.Invocations;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Npgsql;
var referenceData = await LoadReferenceDataAsync(
Environment.GetEnvironmentVariable("REFERENCE_DATA_URL")
?? throw new InvalidOperationException("Set REFERENCE_DATA_URL."));
InvocationsServer.Run(
services => new TopicHandler(
referenceData, services.GetRequiredService<DatabaseConnection>()),
args,
builder =>
{
builder.Services.AddSingleton<DatabaseConnection>();
builder.Services.AddSingleton<IAgentSnapshotLifecycle>(
services => services.GetRequiredService<DatabaseConnection>());
});
// Load shared, immutable data before snapshot capture.
static async Task<IReadOnlyDictionary<string, string>> LoadReferenceDataAsync(
string url)
{
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
return await client.GetFromJsonAsync<Dictionary<string, string>>(url)
?? throw new InvalidOperationException(
"Reference data must be a JSON object.");
}
// Owns the live database connection across the snapshot boundary.
public sealed class DatabaseConnection
: IAgentSnapshotLifecycle, IAsyncDisposable
{
public NpgsqlConnection? Current { get; private set; }
// Keep live database connections out of the captured state.
public Task BeforeSnapshotAsync(CancellationToken cancellationToken) =>
CloseAsync();
// Reconnect with session credentials; don't reload shared data.
public async Task AfterRestoreAsync(
AgentRestoreContext context, CancellationToken cancellationToken)
{
await CloseAsync();
var settings = new NpgsqlConnectionStringBuilder
{
Host = Env("DB_HOST"),
Database = Env("DB_NAME"),
Username = Env("DB_USER"),
Password = Env("DB_PASSWORD"),
SslMode = SslMode.VerifyFull,
RootCertificate = Env("DB_SSLROOTCERT"),
Timeout = 10,
};
var connection = new NpgsqlConnection(settings.ConnectionString);
await connection.OpenAsync(cancellationToken);
Current = connection;
}
// Release the connection when the restored process exits.
public async ValueTask DisposeAsync() => await CloseAsync();
private async Task CloseAsync()
{
if (Current is not null)
{
await Current.DisposeAsync();
Current = null;
}
}
private static string Env(string name) =>
Environment.GetEnvironmentVariable(name)
?? throw new InvalidOperationException($"Set {name}.");
}
public sealed record TopicRequest(string Topic);
public sealed class TopicHandler(
IReadOnlyDictionary<string, string> referenceData,
DatabaseConnection database) : InvocationHandler
{
private static readonly JsonSerializerOptions JsonOptions =
new(JsonSerializerDefaults.Web);
public override async Task HandleAsync(
HttpRequest request,
HttpResponse response,
InvocationContext context,
CancellationToken cancellationToken)
{
var body = await JsonSerializer.DeserializeAsync<TopicRequest>(
request.Body, JsonOptions, cancellationToken);
await using var command = new NpgsqlCommand(
"SELECT current_user", database.Current);
var databaseUser = (string?)await command.ExecuteScalarAsync(
cancellationToken);
await response.WriteAsJsonAsync(
new
{
answer = referenceData[body!.Topic],
database_user = databaseUser,
},
cancellationToken);
}
}
Reference: .NET snapshot lifecycle guidance.
No database connection opens during shared preparation, so the captured state contains the cached data but no live connection. The example registers one DatabaseConnection singleton as both the snapshot lifecycle and the handler's database dependency.
BeforeSnapshotAsync closes the connection if one exists; it's safe when no connection is open. When the host shuts down, the service container disposes the singleton, which closes the connection.
Before AfterRestoreAsync runs, the SDK applies session environment overrides to the process environment. The hook reads the current credentials and connects to PostgreSQL without reloading reference data. It first closes any previous connection so another restore cycle doesn't retain it.
Missing credentials or a failed connection cause the hook to fail. Foundry doesn't forward requests until the after-restore hook succeeds.
Send {"topic": "reset-device"} to get the cached answer and the connected PostgreSQL role from SELECT current_user. No application table is required. The handler assumes the topic exists. A database role isn't the identity of the caller making the request.
Obtain changing values when you need them
Generate request identifiers inside your request handler, not during application startup. An identifier generated before capture is copied into restored sandboxes. Copying a random value doesn't generate another one.
Use the same reasoning for time, identity, credentials, and live resources.
| Value or resource | When to create or refresh it | Why |
|---|---|---|
| Request identifier or caller identity | On each request. | A request must not inherit another request's identifier or authorization context. |
| Current time and deadlines | When the operation starts. | A captured timestamp describes startup, not the current operation. |
| Elapsed-time baseline | Immediately before the work you measure. | A pre-capture timer baseline spans the wrong interval, even with a monotonic clock. |
| Credentials and tokens | Through a provider that refreshes them when needed. | A captured token can expire before or during a session. |
| Instance identifier | After restore. | A startup-generated identifier is part of the shared baseline. |
| Sockets and connection pools | Reconnect after restore; verify the first outbound call. | Captured connections might no longer be usable. |
| Cryptographic random state | Use OS-backed randomness when needed; verify library restore behavior. | Copied generator state can repeat output. |
For example, read a monotonic clock when an operation begins and again when it ends. Don't save the starting value during application startup.
For authentication, distinguish a credential provider from the token it returns. A supported provider can refresh tokens as needed; a bearer token in a global variable can't refresh itself. Refreshing only after restore isn't enough if the session outlives the token. Don't save a caller's identity in a shared client's default headers.
For security-sensitive tokens and identifiers, use supported operating-system-backed randomness when the value is needed, such as Python's secrets module or .NET's RandomNumberGenerator. Also check the snapshot behavior of cryptographic libraries your application uses. Moving a call into request handling doesn't make a library safe if it resumes a copied pseudorandom sequence.
Check startup locally
Before creating a snapshot-enabled version, verify that the application starts successfully and responds to its readiness probe.
Run your hosted agent locally with the Azure Developer CLI with the required dependencies and configuration. The linked guide covers
azd ai agent runand protocol-specific local invocation.Wait for initialization to complete, then check the readiness endpoint:
curl --fail --show-error --include http://localhost:8088/readinessReference: Hosted agent health probe.
Confirm that the response is
200 OK. If startup fails or readiness doesn't succeed, inspect the local application logs and fix the problem before deployment.
Local readiness verifies ordinary startup, not the complete capture-and-restore lifecycle. You can invoke an example without lifecycle hooks locally. An example with lifecycle hooks needs the platform to run its after-restore hook before it can handle requests. Test restoration after deploying the snapshot-enabled version.
Enable snapshots for an agent version
Enable snapshots when creating the version that uses your prepared code. You can't edit existing versions in place.
Select the tab for the tool you use to create agent versions. Each tool sets the same enable_memory_snapshot field on the version definition.
Use azd version 1.37.0 or later with the azure.ai.agents extension version 1.0.0-beta.23. For installation and upgrade instructions, see Install the Azure Developer CLI Foundry extensions.
Prepare your application and its
azure.yamlconfiguration by following Deploy a hosted agent or Deploy a hosted agent from source code. Keep the sample's deployment, protocol, environment, and connection settings.Add
enableMemorySnapshot: trueto your existing hosted agent service inazure.yaml. The following fragment shows where to add the property; it isn't a complete project configuration:services: my-agent: host: azure.ai.agent project: . kind: hosted name: my-agent enableMemorySnapshot: trueReference: Hosted agent service configuration.
In Bash, enable the CLI's snapshot feature switch and deploy the updated agent:
export AZD_ALPHA_ENABLE_AGENTS_MEMORY_SNAPSHOT=true azd deployReference: Azure Developer CLI agent extension memory snapshots.
The feature switch enables CLI support for the setting. The enableMemorySnapshot property opts the agent version in and maps to definition.enable_memory_snapshot in the service API. This configuration supports both code and container-image deployments.
Use azd version 1.37.0 or later with the azure.ai.agents extension version 1.0.0-beta.23. For installation and upgrade instructions, see Install the Azure Developer CLI Foundry extensions.
Prepare your application and its
azure.yamlconfiguration by following Deploy a hosted agent or Deploy a hosted agent from source code. Keep the sample's deployment, protocol, environment, and connection settings.Add
enableMemorySnapshot: trueto your existing hosted agent service inazure.yaml. The following fragment shows where to add the property; it isn't a complete project configuration:services: my-agent: host: azure.ai.agent project: . kind: hosted name: my-agent enableMemorySnapshot: trueReference: Hosted agent service configuration.
In Bash, enable the CLI's snapshot feature switch and deploy the updated agent:
export AZD_ALPHA_ENABLE_AGENTS_MEMORY_SNAPSHOT=true azd deployReference: Azure Developer CLI agent extension memory snapshots.
The feature switch enables CLI support for the setting. The enableMemorySnapshot property opts the agent version in and maps to definition.enable_memory_snapshot in the service API. This configuration supports both code and container-image deployments.
Verify version readiness
Poll the version status until it reaches active or failed, as described in Deploy a hosted agent. Snapshot preparation is asynchronous. Treat creating as pending, active as ready, and failed as an error to inspect. A successful create response alone doesn't indicate readiness.
Invoke the agent only after the version becomes active. Use the protocol and request shape your handler supports. For azd invocation commands, JSON request files, and version selection, see Invoke a hosted agent with the Azure Developer CLI.
Check latency and restore behavior
Measure the time from starting a new session to its first useful response, not just time inside the request handler. Compare the same workload with and without snapshots, by using the same image, compute configuration, and request input.
- Start separate new sessions and record client-observed startup latency over repeated trials. For
azdcommands to start a new session or reuse a session ID, see Manage sessions. - Include the first database, model, or tool call. A client that connects lazily can defer setup cost until that call.
- Send requests in two sessions, and confirm that request identifiers and other per-session values differ.
- Change a credential or mutable configuration value, and confirm that later calls use the current value.
- Resume a session after idle suspension, and confirm that required state reloads from external storage.
- Deploy a test version whose after-restore hook fails, for example because a required credential is missing. Confirm that invocations return
session_restore_failedinstead of reaching an uninitialized agent.
Verify that your application's dependencies work after restoration. Successful initialization before capture alone doesn't establish that a library or client works after restore.
Troubleshoot snapshot failures
If snapshot capture fails, check the error message in the agent version API response. Preparation is asynchronous, so check the version response when its status becomes failed, not just the initial create response.
An initial terminal capture failure fails the snapshot-enabled version; the service doesn't silently switch it to ordinary cold startup. A restore initialization failure prevents normal request processing for that restore cycle.
Also check the application logs in the Application Insights resource connected to your Foundry project. You must configure project monitoring for the SDK to export telemetry there; see Configure hosted agent telemetry. You can also check hosted agent console and system logs for startup failures. Keep error reporting visible without logging tokens or session environment overrides.
| Symptom | What to check |
|---|---|
Snapshot capture fails and the version status is failed. |
Read the error message in the version API response. Check application logs for initialization, readiness, and before-snapshot hook errors. Confirm the application starts and passes its readiness check locally. |
An invocation returns session_restore_failed. |
Check the after-restore hook, current credentials, and reconnections. A hook failure can remain recorded for that restore cycle; repeated invocations don't necessarily rerun the hook. |
| The first request is still slow. | Check work deferred until the first call or repeated in the after-restore hook. Measure initialization separately from inference and remote-service latency. |
| Session state is missing when the session resumes after idle suspension. | Persist state externally and reload it on resumption. The version baseline isn't a checkpoint of the session's latest memory or files. |