Install
$ agentstack add skill-aiappsgbb-awesome-gbb-foundry-memory ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Foundry Memory
Foundry Memory Store is the native Azure AI Foundry feature for persistent agent memory across sessions. It gives a Foundry agent a managed long-term memory layer instead of requiring an external sidecar such as Mem0.
It stores three memory types:
- User profiles — durable facts and preferences about a user (for example,
preferred units, UI settings, loyalty program, or role context).
- Chat summaries — distilled cross-session summaries of prior threads so a
later conversation can resume without replaying the full transcript.
- Procedural memory — codified procedures the agent has learned through
experience (for example, "when the user asks for a refund, always confirm the order ID first"). Procedural memory is opt-in per store via procedural_memory_enabled=True.
Use it when the memory is user-scoped, conversational, and agent-native. If the problem is document grounding or enterprise RAG over files, use [foundry-iq](../foundry-iq/) instead.
1. Overview
Foundry Memory is a managed long-term memory subsystem inside Foundry Agent Service. The service extracts salient facts from conversations, consolidates duplicates, and makes the results searchable for later turns or later sessions.
Key platform facts:
- SDK floor:
azure-ai-projects>=2.0.0 - Python entry point:
project_client.beta.memory_stores - REST API version:
2025-11-15-preview - Native replacement for older Mem0 patterns: prefer Foundry Memory when
the workload already lives in Foundry Agent Service
- Agent integration: attach the
memory_search_previewtool so the agent
can read and write memory automatically during conversations
2. Prerequisites
Before you create a memory store, make sure the project has:
- A Foundry project endpoint such as
https://.services.ai.azure.com/api/projects/
- A compatible chat model deployment for extraction / consolidation
- A compatible embedding model deployment for semantic retrieval
azure-ai-projects>=2.0.0plusazure-identityfor Python- Preview API access for
2025-11-15-preview
Embedding model requirement
Deploy text-embedding-3-small or text-embedding-3-large in the same project (or via a connected resource). Memory retrieval uses that embedding model to index and recall relevant memories.
> Sweden Central: embedding deployments MUST use SKU GlobalStandard, > not the default Standard — ARM rejects Standard with > InvalidResourceProperties: Sku is not supported in this region. Other > regions may impose similar constraints; verify the SKU-by-region > availability table in the Foundry / Cognitive Services capacity docs > before deploying elsewhere. (AGENTS.md § 9.7 Pattern 21.)
Supported regions (May 2026 field audit)
australiaeast, canadacentral, centralus, eastus, eastus2, francecentral, germanywestcentral, japaneast, koreacentral, northcentralus, norwayeast, polandcentral, southcentralus, swedencentral, switzerlandnorth, uaenorth, westeurope, westus3
If your project is outside those regions, treat memory as unavailable until the preview footprint expands.
3. Creating a memory store
Create one memory store per agent or per clear isolation boundary. Keep the store focused so profile extraction and summary retrieval stay relevant.
Python
import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
MemoryStoreDefaultDefinition,
MemoryStoreDefaultOptions,
)
from azure.identity import DefaultAzureCredential
project_client = AIProjectClient(
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=DefaultAzureCredential(),
)
definition = MemoryStoreDefaultDefinition(
chat_model=os.environ["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"],
embedding_model=os.environ["MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME"],
options=MemoryStoreDefaultOptions(
user_profile_enabled=True,
chat_summary_enabled=True,
user_profile_details=(
"Remember stable user preferences and history; avoid secrets, "
"credentials, and irrelevant personal data."
),
),
)
store = project_client.beta.memory_stores.create(
name="",
definition=definition,
description="Persistent memory store for a Foundry agent",
)
print(store.id)
REST
API_VERSION="2025-11-15-preview"
ACCESS_TOKEN="$(az account get-access-token \
--resource https://ai.azure.com/ \
--query accessToken -o tsv)"
curl -X POST \
"https://.services.ai.azure.com/api/projects//memory_stores?api-version=${API_VERSION}" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"name": "",
"description": "Persistent memory store for a Foundry agent",
"definition": {
"kind": "default",
"chat_model": "",
"embedding_model": "text-embedding-3-small",
"options": {
"user_profile_enabled": true,
"chat_summary_enabled": true,
"user_profile_details": "Remember stable preferences; avoid secrets."
}
}
}'
4. Adding memories
The low-level API adds memory by submitting conversation turns. Foundry then extracts profile facts and summary memories from those turns.
User profiles + chat summaries
scope = ""
items = [
{
"type": "message",
"role": "user",
"content": "I prefer dark mode, metric units, and vegetarian meals.",
},
{
"type": "message",
"role": "assistant",
"content": "Understood. I will use those preferences in later sessions.",
},
]
update_poller = project_client.beta.memory_stores.begin_update_memories(
name="",
scope=scope,
items=items,
update_delay=0,
)
update_result = update_poller.result()
for operation in update_result.memory_operations:
print(operation.kind, operation.memory_item.content)
REST shape:
curl -X POST \
"https://.services.ai.azure.com/api/projects//memory_stores/:update_memories?api-version=2025-11-15-preview" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"scope": "",
"items": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "I prefer dark mode, metric units, and vegetarian meals."
}
]
}
],
"update_delay": 0
}'
Notes:
- User profile memory is the stable fact layer extracted from those turns
- Chat summary memory is the summarized thread layer extracted after the
conversation settles
- Writes are asynchronous;
update_delaycontrols when long-term memory is
committed after inactivity
5. Searching / retrieving memories
Search is semantic. Use it either to preload stable profile facts at session start or to fetch relevant summary memories for the current turn.
from azure.ai.projects.models import MemorySearchOptions
query_item = {
"type": "message",
"role": "user",
"content": "What preferences has this user shared before?",
}
search_response = project_client.beta.memory_stores.search_memories(
name="",
scope="",
items=[query_item],
options=MemorySearchOptions(max_memories=5),
)
for memory in search_response.memories:
print(memory.memory_item.content)
REST search:
curl -X POST \
"https://.services.ai.azure.com/api/projects//memory_stores/:search_memories?api-version=2025-11-15-preview" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"scope": "",
"items": [
{
"type": "message",
"role": "user",
"content": [
{
"type": "input_text",
"text": "What preferences has this user shared before?"
}
]
}
],
"options": {
"max_memories": 5
}
}'
Retrieval pattern:
- Static profile recall: call search with a
scopebut no new items when
you want baseline user facts at conversation start
- Contextual recall: include the latest turn in
itemsto retrieve the most
relevant summaries for the current question
6. Scope isolation
Scope is the boundary that prevents one user's memory from bleeding into another's.
Tool-based auto-resolution
When memory is attached as an agent tool, set:
scope: "{{$userId}}"in the tool definitionx-memory-user-id:on response calls when your backend is acting
on behalf of a user
If the header is absent, Foundry falls back to the caller's Microsoft Entra identity and resolves scope from tenant ID + object ID.
Low-level API behavior
For direct memory store API calls, you must provide scope explicitly. The low-level API does not auto-resolve scope from Entra.
Rule of thumb:
- tool path =
{{$userId}}+ optionalx-memory-user-id - direct API path = explicit
scope=""
7. Using with hosted agents
Attach the memory store as a tool so the hosted agent reads and writes memory without manual update/search calls in your application logic.
from azure.ai.projects.models import MemorySearchPreviewTool, PromptAgentDefinition
memory_tool = MemorySearchPreviewTool(
memory_store_name="",
scope="{{$userId}}",
update_delay=1,
)
agent = project_client.agents.create_version(
agent_name="memory-enabled-agent",
definition=PromptAgentDefinition(
model=os.environ["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"],
instructions="Use stored profile and chat summary memory to personalize responses.",
tools=[memory_tool],
),
)
response = project_client.get_openai_client().responses.create(
conversation="",
input="Please use my saved preferences.",
extra_body={"agent_reference": {"name": agent.name, "type": "agent_reference"}},
extra_headers={"x-memory-user-id": ""},
)
Operationally:
- the agent injects static profile memory at conversation start
- it retrieves contextual memories per turn
- it schedules memory writes after inactivity using
update_delay
RBAC requirement (Pattern 23 — server-side worker identity): Memory consolidation runs as the project's system-assigned managed identity (NOT the caller's identity). That identity needs Cognitive Services OpenAI User AND Cognitive Services User at the Foundry account scope to call the chat deployment. The project SAMI is created with ACR roles only — the two Cog roles must be granted explicitly. Symptom of omission: 401 from the memory worker on its first consolidation pass, with the deploy/invoke path superficially succeeding. See AGENTS.md § 9.7 Pattern 23 for the canonical grant script.
This is the cleanest replacement for external memory middleware when the agent already runs on Foundry.
8. Multi-language SDKs
| Language | Package | Primary surface | |---|---|---| | Python | azure-ai-projects | project_client.beta.memory_stores | | C# | Azure.AI.Projects | projectClient.MemoryStores | | TypeScript | @azure/ai-projects | project.beta.memoryStores |
Python
project_client.beta.memory_stores.create(...)
project_client.beta.memory_stores.begin_update_memories(...)
project_client.beta.memory_stores.search_memories(...)
C#
projectClient.MemoryStores.CreateMemoryStore(...);
projectClient.MemoryStores.WaitForMemoriesUpdate(...);
projectClient.MemoryStores.SearchMemories(...);
TypeScript
await project.beta.memoryStores.create(...);
const poller = project.beta.memoryStores.updateMemories(...);
await project.beta.memoryStores.searchMemories(...);
9. Procedural memory
Procedural memory is the third memory type alongside user profiles and chat summaries. It stores codified procedures the agent has learned through experience — patterns like "always confirm the order ID before issuing a refund", "for premium-tier users, skip the upsell prompt", or "when a customer mentions an outage, check the status page before opening a ticket".
Procedural memory is opt-in per store. Enable it on MemoryStoreDefaultOptions at create-time:
Python
import os
from azure.ai.projects import AIProjectClient
from azure.ai.projects.models import (
MemoryStoreDefaultDefinition,
MemoryStoreDefaultOptions,
)
from azure.identity import DefaultAzureCredential
project_client = AIProjectClient(
endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
credential=DefaultAzureCredential(),
)
definition = MemoryStoreDefaultDefinition(
chat_model=os.environ["MEMORY_STORE_CHAT_MODEL_DEPLOYMENT_NAME"],
embedding_model=os.environ["MEMORY_STORE_EMBEDDING_MODEL_DEPLOYMENT_NAME"],
options=MemoryStoreDefaultOptions(
user_profile_enabled=True,
chat_summary_enabled=True,
procedural_memory_enabled=True,
user_profile_details=(
"Remember stable user preferences and history; avoid secrets, "
"credentials, and irrelevant personal data."
),
),
)
store = project_client.beta.memory_stores.create(
name="",
definition=definition,
description="Persistent memory store with procedural memory enabled",
)
Behavioral contract
- Procedural memory items have
kind="procedural"when returned by
list_memories or search_memories.
- Foundry extracts procedural memories from conversation turns the same way it
extracts profile facts and summaries — submit turns via begin_update_memories (see § 4), then wait for the update_delay window.
- Procedural memory is scope-isolated like the other types — always pass a
stable scope (typically {"user_id": ""}) so an agent's learned procedures stay separated per user / per tenant.
- Enabling procedural memory does not retroactively populate the store from
prior conversations. It applies only to turns submitted after the flag is on.
Keep user_profile_details (or the procedural-side hints) focused on the domain the agent operates in. Procedural memory can be poisoned by adversarial prompts the same way as user profiles — apply the input-filtering and no-secrets rules from § 13.
10. CRUD on memories via direct API
In addition to search_memories (§ 5) for retrieval and begin_update_memories (§ 4) for write, the direct API surfaces store-level CRUD and a list_memories helper for browsing the current contents of a scope.
Store-level CRUD
# Get a store by name (raises ResourceNotFoundError if absent)
store = project_client.beta.memory_stores.get(name="")
# List all stores in the project
for s in project_client.beta.memory_stores.list():
print(s.name, s.description)
# Delete a store (idempotent — returns an object with .deleted boolean)
result = project_client.beta.memory_stores.delete(name="")
assert result.deleted
Listing memories inside a store
list_memories enumerates the memory items Foundry has extracted for a given scope. Use it for audit, debugging, and admin UIs — for runtime retrieval, prefer search_memories (§ 5) which returns semantically-ranked items.
for item in project_client.beta.memory_stores.list_memories(
name="",
scope={"user_id": ""},
):
print(item.memory_id, item.kind, item.content)
kind is one of "user_profile", "chat_summary", or "procedural" — filter client-side when you only want one type.
Per-item deletion
The current preview surface does not expose a per-item delete_memory(memory_id) call. To prune individual memories, the supported paths are:
- Store-level delete + recreate for full reset (acceptable for tests and
rebuilds; destructive in production).
- TTL-based expiry (see § 11) — set a
default_ttl_secondsso unused
memories self-evic
…
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: aiappsgbb
- Source: aiappsgbb/awesome-gbb
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.