Items marked (preview) in this article are currently in public preview. This preview is provided without a service-level agreement, and we don’t recommend it for production workloads. Certain features might not be supported or might have constrained capabilities. For more information, see Supplemental Terms of Use for Microsoft Azure Previews.
What to keep in the state store
A hosted agent’s compute is ephemeral. When the container restarts or the platform evicts it after an idle period, your agent loses anything it writes to local disk outside a session. The state store holds the state that must outlive the container. Typical contents include:- Framework checkpoints, so a bring-your-own agent framework such as LangGraph or Microsoft Agent Framework can resume its own graph or workflow state.
- Conversation history that your agent manages itself, which is the Invocations-protocol case where the platform doesn’t store history for you.
- Generated artifacts and intermediate work that a later turn needs.
- Per-user profiles, preferences, and other long-lived application data.
Stores
AFoundryStateStore client binds to one store name that you choose. That name serves as both the store’s identity and its outermost partition. A store holds keyed JSON items that you can read, write, delete, and list.
- Store name is the identity: You can’t change a store name after creation, so choose a stable naming scheme upfront.
- Get-or-create is the store-level operation: A single get-or-create call fetches the store or creates it when it’s absent. Creation options apply only on first creation, so the service ignores them when the store already exists. An item write doesn’t create a missing store.
- Item lifetime: A store-level idle window removes items. The default is 30 days, and you can configure a store so that items never expire. Writes renew the window, and reads don’t. You set this option at creation.
Partition data
The store gives you two independent ways to partition data, and most agents need only one of them.- By store name: Every store name is its own partition. Names can contain
/, so you can use it as a hierarchy separator, as incheckpoints/thread-abcorworkflow-state/run-42. Choose this partition when the code that reads an item always has the partition identifier available to rebuild the name. - By end user: A store created with user isolation partitions its items per end user, so a single store name is safe to share across the users of a multitenant agent. Choose this partition when the same store name serves more than one user. You set this option at creation, and the store resolves the user from the request rather than from anything your code passes. For details, see Caller identity.
Don’t encode an end-user identifier in a store name. Store names appear in operational surfaces such as logs and error messages, and a name your own code builds isn’t a verified identity. Use user isolation for per-user partitioning, so the platform enforces the boundary from the caller it established rather than from a value your agent supplies.
Caller identity
The state store applies the hosted agent identity model. On container protocol 2.0.0, each request the platform routes to your agent carries anx-agent-foundry-call-id header that identifies the caller, and the store resolves the acting end user from it. The Foundry SDKs forward the header on store calls for you, so most agents never handle it directly.
Two consequences matter when you design with it:
- User isolation derives from the call ID: In a user-isolated store, the partition comes from the caller the platform identified, not from anything your agent passes. A hosted agent doesn’t supply an end-user identifier of its own. If your runtime issues its own HTTP requests instead of using an SDK client, forward the header unchanged, and treat the value as opaque.
- Local runs don’t support user isolation: The platform doesn’t provide the call ID off-platform. Neither the Python nor .NET SDK can enforce user isolation when you run the container locally. Test user-isolation boundaries with a deployed hosted agent.
Carry the call ID into deferred work
Item operations act on behalf of a caller, and store operations don’t.
By default an item operation uses the call ID of the request it runs inside, which is what you want for work that finishes during that request.
Work that outlives the request has no ambient call ID to inherit, such as background processing or a step that resumes in a later process lifetime. Every item operation accepts an explicit call ID for this case. Capture it while you still have the request, carry it alongside the work, and pass it back on each item operation, so those operations keep acting for the original caller.
The call ID identifies the caller of the current request, and it only partitions the items inside a user-isolated store. It doesn’t partition anything else your container stores. For files, database rows, or caches that your own code owns, key them by the session ID and the user ID, as described in Multiplex users in a shared session.
Items
An item is a key and a JSON value, with optional string tags.- Values are your application JSON: The store doesn’t interpret an item value. Serialize your framework or domain models explicitly.
- Tags are for filtering: Tags are simple string labels, matched with AND when you list keys. Promote only the fields you need to filter on.
- Listing returns keys only: A page of keys is cheap even when the values are large, so listing and fetching are separate steps.
- Optimistic concurrency: Every item carries an ETag. Use an
If-Matchprecondition for read-modify-write operations on mutable items, such as counters, where a lost update would corrupt state. A failed precondition reports the current ETag. - Append-only checkpoints don’t need preconditions: When each save writes a fresh key, there’s no write contention, so the checkpoint path never needs
If-Match.
Create a store and items
The following example gets or creates a user-isolated store, writes an item, reads it back, and lists keys by tag. Get-or-create is the only store-level call an agent needs: it fetches the store, or creates it with the options you pass when the store is absent.Service limits
The service enforces these limits. If you violate a limit, the service returns400 Bad Request and names the invalid field in the error message.