# Foundry Memory

> >

- **Type:** Skill
- **Install:** `agentstack add skill-aiappsgbb-awesome-gbb-foundry-memory`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [aiappsgbb](https://agentstack.voostack.com/s/aiappsgbb)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [aiappsgbb](https://github.com/aiappsgbb)
- **Source:** https://github.com/aiappsgbb/awesome-gbb/tree/main/skills/foundry-memory

## Install

```sh
agentstack add skill-aiappsgbb-awesome-gbb-foundry-memory
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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:

1. **User profiles** — durable facts and preferences about a user (for example,
   preferred units, UI settings, loyalty program, or role context).
2. **Chat summaries** — distilled cross-session summaries of prior threads so a
   later conversation can resume without replaying the full transcript.
3. **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_preview` tool 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.0` plus `azure-identity` for 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

```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

```bash
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

```python
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:

```bash
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_delay` controls 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.

```python
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:

```bash
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 `scope` but no new items when
  you want baseline user facts at conversation start
- **Contextual recall:** include the latest turn in `items` to 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 definition
- `x-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}}` + optional `x-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.

```python
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

```python
project_client.beta.memory_stores.create(...)
project_client.beta.memory_stores.begin_update_memories(...)
project_client.beta.memory_stores.search_memories(...)
```

### C#

```csharp
projectClient.MemoryStores.CreateMemoryStore(...);
projectClient.MemoryStores.WaitForMemoriesUpdate(...);
projectClient.MemoryStores.SearchMemories(...);
```

### TypeScript

```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

```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

```python
# 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.

```python
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_seconds` so 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](https://github.com/aiappsgbb)
- **Source:** [aiappsgbb/awesome-gbb](https://github.com/aiappsgbb/awesome-gbb)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** yes
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-aiappsgbb-awesome-gbb-foundry-memory
- Seller: https://agentstack.voostack.com/s/aiappsgbb
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
