Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.maximem.ai/llms.txt

Use this file to discover all available pages before exploring further.

Add persistent memory to a Microsoft Agent Framework (MAF) agent through two providers: a context provider that injects semantic memory before each turn and records turns after, and a history provider that handles verbatim conversation persistence.

Overview

This guide shows how to add Synap to a MAF application to build agents that:
  • Inject the most relevant memories as a system message at the start of each turn
  • Record completed turns back to Synap for future retrieval
  • Persist and replay the full verbatim conversation history when full transcript visibility is needed
The Synap MAF integration ships two providers — each plugs into MAF’s context_providers slot and handles one axis of memory.
ClassRolePurpose
SynapContextProviderSemanticInjects relevant memories before each turn; records turns after
SynapHistoryProviderVerbatimPersists and reloads the full conversation transcript

Setup

Install the package alongside MAF:
pip install maximem-synap-microsoft-agent azure-ai-agents
Configure your API key. Generate one from the Synap Dashboard.
.env
SYNAP_API_KEY=synap_your_key_here
AZURE_AI_ENDPOINT=your-endpoint
Initialize the SDK once at application startup:
from maximem_synap import MaximemSynapSDK

sdk = MaximemSynapSDK()
await sdk.initialize()
See SDK Initialization for the full lifecycle and configuration options.

Basic integration

The smallest useful integration wires SynapContextProvider into a MAF agent. Each turn now starts with the most relevant Synap memories injected as a system message, and ends with the completed turn ingested back into Synap:
import os
from azure.ai.agents import AgentsClient
from synap_microsoft_agent import SynapContextProvider

client = AgentsClient(endpoint=os.environ["AZURE_AI_ENDPOINT"])

agent = client.as_agent(
    context_providers=[
        SynapContextProvider(
            sdk=sdk,
            user_id="alice",
            customer_id="acme",   # optional — required for B2B instances
            max_context_results=6,
        ),
    ],
)

response = await agent.run("What were the outcomes from my last meeting?")
The provider handles both the read (context injection) and the write (turn ingestion). Reads degrade gracefully on Synap outages — empty context is injected, the error is logged, and the agent still answers. Writes surface failures explicitly so silent data loss is impossible. For verbatim transcript persistence on top of semantic memory, layer in SynapHistoryProvider — see below.

Core concepts

Context provider

SynapContextProvider runs on MAF’s before_turn and after_turn hooks:
  1. Before each turn — fetches relevant memories for the incoming message and appends them as a system context message.
  2. After each turn — ingests the full user/assistant exchange back into Synap.
from synap_microsoft_agent import SynapContextProvider

ctx = SynapContextProvider(
    sdk=sdk,
    user_id="alice",
    customer_id="acme",
    max_context_results=6,
)
This is the standard provider for most agents — it gives the model awareness of long-term context without requiring you to manage the transcript.

History provider

SynapHistoryProvider handles the verbatim conversation transcript. Use it when the model needs to see the full prior message history (not just semantic snippets):
from synap_microsoft_agent import SynapHistoryProvider

hist = SynapHistoryProvider(
    sdk=sdk,
    user_id="alice",
    conversation_id="thread-001",
)
The provider exposes two methods that MAF calls automatically:
MethodBehavior
load(thread_id)Fetches prior messages from Synap and restores them to the MAF thread
save(thread_id, messages)Writes new messages to Synap after each turn
SynapHistoryProvider is orthogonal to SynapContextProvider — one stores semantic memory, the other stores the literal transcript. Most production agents use both.

Complete example: agent with both memory axes

The pattern below combines the two providers so the agent gets both semantic context and full transcript replay:
import os
from azure.ai.agents import AgentsClient
from synap_microsoft_agent import SynapContextProvider, SynapHistoryProvider


def build_agent(sdk, client: AgentsClient, user_id: str, conversation_id: str, customer_id: str | None = None):
    return client.as_agent(
        context_providers=[
            SynapContextProvider(
                sdk=sdk,
                user_id=user_id,
                customer_id=customer_id,
                max_context_results=6,
            ),
            SynapHistoryProvider(
                sdk=sdk,
                user_id=user_id,
                conversation_id=conversation_id,
            ),
        ],
    )


# Usage
client = AgentsClient(endpoint=os.environ["AZURE_AI_ENDPOINT"])
agent = build_agent(sdk, client, user_id="alice", conversation_id="thread-001", customer_id="acme")

response = await agent.run("What did we agree on for the Q2 roadmap?")
# Context provider injects semantic memory; history provider gives the model the full conversation transcript.
Three things to notice in this pattern:
  1. The two providers serve different needs. Semantic memory tells the agent what’s relevant; verbatim history tells it what was said.
  2. conversation_id only matters to the history provider. The context provider pulls user-level memories regardless of thread.
  3. Failure semantics split. Reads (context fetch, history load) degrade gracefully; writes (turn ingest, history save) raise on failure so silent data loss is impossible.

Advanced patterns

Multi-tenant scoping

Both providers accept the standard scoping triple — user_id (required), optional customer_id, optional conversation_id. customer_id is required on B2B Synap instances and ignored on single-tenant ones. See Memory Scopes.
ctx = SynapContextProvider(sdk=sdk, user_id="alice", customer_id="acme")
For multi-tenant services, build providers per request rather than caching them globally — each agent should have its scope baked in.

Choosing between context-only and history-only

Some agents don’t need both:
  • Context only — concise agents that benefit from semantic recall but where full transcripts would blow the context budget.
  • History only — short-lived agents (single session) that need verbatim replay but no long-term memory pool.
  • Both — production agents that maintain ongoing relationships with users across many sessions.

Failure semantics

The integration follows the Synap-wide contract:
  • SynapContextProvider reads degrade gracefully — empty context is injected and the error logged.
  • SynapContextProvider writes surface failures — turn ingestion raises SynapIntegrationError so callers know persistence failed.
  • SynapHistoryProvider.load degrades gracefully — returns an empty message list and logs the error.
  • SynapHistoryProvider.save surfaces failures — raises SynapIntegrationError.
This is by design: read failures shouldn’t break a user-facing turn, but silent write failures would corrupt the memory pool.

Next steps

Semantic Kernel

Kernel plugin for Microsoft Semantic Kernel.

NeMo Agent Toolkit

MemoryEditor for NVIDIA NeMo workflows.

Context Fetch

The retrieval API behind SynapContextProvider — modes, scopes, and response shapes.

Memory Scopes

How user_id, customer_id, and conversation_id interact across reads.