Microsoft Agent Framework Integration

This guide explains how to use Neo4j Agent Memory with Microsoft Agent Framework to build agents with persistent memory, graph-enhanced context retrieval, and Graph Data Science (GDS) algorithms for advanced recommendations.

This integration targets Microsoft Agent Framework v1.0.0b260212 (preview). APIs may change before GA release (expected Q1 2026). See API Compatibility for version requirements and migration guidance.

Overview

The Microsoft Agent Framework integration provides:

  • ContextProvider: Automatic memory injection before agent invocation

  • ChatMessageStore: Persistent conversation history in Neo4j

  • Memory tools: Search, preferences, knowledge graph queries

  • GDS integration: PageRank, community detection, shortest path with graceful fallback

  • Reasoning traces: Capture agent execution patterns for learning

Installation

Install with Microsoft Agent Framework support:

pip install neo4j-agent-memory[microsoft-agent]

This installs:

  • agent-framework>=1.0.0b - Microsoft Agent Framework

  • Required Neo4j dependencies

Quick Start

Using Neo4jContextProvider

The Neo4jContextProvider automatically injects relevant memory context before each agent invocation:

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.microsoft_agent import Neo4jContextProvider
from agent_framework.azure import AzureOpenAIResponsesClient

settings = MemorySettings(
    neo4j={"uri": "bolt://localhost:7687", "username": "neo4j", "password": "password"},
    embedding={"provider": "openai", "api_key": "sk-..."},
)

async with MemoryClient(settings) as client:
    # Create context provider
    provider = Neo4jContextProvider(
        memory_client=client,
        session_id="user-123",
        include_short_term=True,   # Recent conversation
        include_long_term=True,    # Entities and preferences
        include_reasoning=True,    # Similar past traces
    )

    # Create agent with memory
    chat_client = AzureOpenAIResponsesClient(model="gpt-4")
    agent = chat_client.as_agent(
        name="assistant",
        instructions="You are a helpful assistant.",
        context_providers=[provider],
    )

    # Use the agent - context is automatically injected
    response = await agent.run("What did we discuss earlier?")

Using Neo4jChatMessageStore

Store conversation history with automatic entity extraction:

from neo4j_agent_memory.integrations.microsoft_agent import Neo4jChatMessageStore

async with MemoryClient(settings) as client:
    store = Neo4jChatMessageStore(
        memory_client=client,
        session_id="user-123",
        extract_entities=True,      # Extract entities from messages
        generate_embeddings=True,   # Generate embeddings for search
    )

    # Add messages
    await store.add_messages([
        Message("user", ["I love Nike running shoes"]),
        Message("assistant", ["Nike makes great running shoes!"]),
    ])

    # List messages
    messages = await store.list_messages()

    # Serialize for persistence
    state = store.serialize()

    # Deserialize later
    new_store = Neo4jChatMessageStore.deserialize(state, memory_client=client)

Using Neo4jMicrosoftMemory (Unified Interface)

For convenience, use the unified interface that combines both:

from neo4j_agent_memory.integrations.microsoft_agent import Neo4jMicrosoftMemory

async with MemoryClient(settings) as client:
    memory = Neo4jMicrosoftMemory(
        memory_client=client,
        session_id="user-123",
        user_id="user-456",  # Optional for personalization
        include_short_term=True,
        include_long_term=True,
        include_reasoning=True,
        max_context_items=15,
        extract_entities=True,
    )

    # Use context provider with agent
    agent = chat_client.as_agent(
        name="assistant",
        context_providers=[memory.context_provider],
    )

    # Direct memory operations
    await memory.save_message("user", "Hello!")
    context = await memory.get_context("user query")
    results = await memory.search_memory("search term")

Memory Tools

Create callable function tools for agent memory operations. The framework auto-invokes these tools during agent execution — no manual dispatch needed:

from neo4j_agent_memory.integrations.microsoft_agent import create_memory_tools

# Create all memory tools bound to a memory instance
tools = create_memory_tools(
    memory,                        # Neo4jMicrosoftMemory instance (required)
    include_gds_tools=True,        # Include GDS algorithm tools (default: True)
)

# Use with agent — framework auto-invokes tools
agent = chat_client.as_agent(
    name="assistant",
    tools=tools,
    context_providers=[memory.context_provider],
)

Available Tools

Tool Description

search_memory

Search conversation history, entities, and preferences

remember_preference

Save a user preference (brand, style, budget, etc.)

recall_preferences

Retrieve preferences by category or search query

search_knowledge

Query the entity knowledge graph

remember_fact

Save a factual SPO triple (subject-predicate-object)

find_similar_tasks

Find similar past reasoning traces

find_connection_path

Find shortest path between two entities (GDS)

find_similar_items

Find similar entities using graph similarity (GDS)

find_important_entities

Get most important entities by PageRank (GDS)

Tool Execution

When using create_memory_tools(), tools are callable FunctionTool instances that the agent framework auto-invokes during agent.run(). No manual dispatch is needed — the framework calls the tool functions directly and feeds results back to the model.

The legacy execute_memory_tool() function is deprecated. Use create_memory_tools() instead, which returns callable tools that the framework invokes automatically.

GDS Integration

Neo4j Graph Data Science algorithms enhance recommendations:

from neo4j_agent_memory.integrations.microsoft_agent import (
    GDSConfig,
    GDSAlgorithm,
    GDSIntegration,
)

# Configure GDS
gds_config = GDSConfig(
    enabled=True,
    use_pagerank_for_ranking=True,     # Rank entities by importance
    pagerank_weight=0.3,               # Weight for PageRank scores
    use_community_grouping=True,       # Group related entities
    expose_as_tools=[                  # Make available as agent tools
        GDSAlgorithm.SHORTEST_PATH,
        GDSAlgorithm.NODE_SIMILARITY,
        GDSAlgorithm.PAGERANK,
    ],
    fallback_to_basic=True,            # Use Cypher if GDS unavailable
    warn_on_fallback=True,             # Log warning when falling back
)

# Create memory with GDS
memory = Neo4jMicrosoftMemory(
    memory_client=client,
    session_id="user-123",
    gds_config=gds_config,
)

# Use GDS directly
if memory.gds:
    # Find path between entities
    path = await memory.gds.find_shortest_path("Nike", "Running Shoes")

    # Find similar entities
    similar = await memory.gds.find_similar_entities("Nike Air Max", limit=5)

    # Get important entities
    important = await memory.gds.get_central_entities(limit=10)

GDS Fallback Behavior

When GDS library is not installed:

Algorithm Fallback Behavior

PageRank

Uses degree centrality (relationship count)

Community Detection

Uses connected components via Cypher

Node Similarity

Uses Jaccard similarity on shared relationships

Shortest Path

Uses native Cypher shortestPath()

Reasoning Traces

Capture agent execution patterns:

from neo4j_agent_memory.integrations.microsoft_agent import (
    record_agent_trace,
    get_similar_traces,
    format_traces_for_prompt,
)

# Record agent execution
await record_agent_trace(
    memory=memory,
    messages=[
        {"role": "user", "content": "Find running shoes under $150"},
        {"role": "assistant", "content": "Recommended Nike Pegasus 40 ($130)"},
    ],
    task="Find running shoes under $150",
    tool_calls=[
        {"name": "search_products", "arguments": {"query": "running shoes"}, "result": "..."},
        {"name": "recall_preferences", "arguments": {"category": "brand"}, "result": "Nike"},
    ],
    outcome="success",
    success=True,
)

# Find similar past tasks
traces = await get_similar_traces(
    memory=memory,
    task="Find shoes matching preferences",
    limit=3,
)

# Format for system prompt
experience = format_traces_for_prompt(traces)

Context Composition

The before_run() hook composes context from all memory types:

## Recent Conversation
[Recent messages relevant to current query]

## Known Preferences
- Brand: Nike
- Budget: Under $150
- Style: Running shoes

## Relevant Entities
- Nike Air Max 90 (Product): Iconic style, $130
- Nike Pegasus 40 (Product): Running shoe, $130

## Past Experience
Similar task: "Find running shoes" - Successfully recommended Pegasus

Serialization

Context providers and message stores support serialization for persistence:

# Serialize state
provider_state = provider.serialize()
store_state = store.serialize()

# Save to Redis, database, etc.
await redis.set(f"provider:{thread_id}", json.dumps(provider_state))
await redis.set(f"store:{thread_id}", json.dumps(store_state))

# Later: restore state
provider_state = json.loads(await redis.get(f"provider:{thread_id}"))
store_state = json.loads(await redis.get(f"store:{thread_id}"))

# Deserialize (requires fresh MemoryClient)
provider = Neo4jContextProvider.deserialize(provider_state, memory_client=client)
store = Neo4jChatMessageStore.deserialize(store_state, memory_client=client)

Complete Example

Here’s a complete shopping assistant example. With callable FunctionTool instances, the framework auto-invokes tools during agent.run() — no manual dispatch needed:

import asyncio
from agent_framework import Message
from agent_framework.azure import AzureOpenAIResponsesClient

from neo4j_agent_memory import MemoryClient, MemorySettings
from neo4j_agent_memory.integrations.microsoft_agent import (
    Neo4jMicrosoftMemory,
    GDSConfig,
    GDSAlgorithm,
    create_memory_tools,
    record_agent_trace,
)


async def main():
    settings = MemorySettings(
        neo4j={"uri": "bolt://localhost:7687", "username": "neo4j", "password": "password"},
        embedding={"provider": "openai", "api_key": "sk-..."},
    )

    gds_config = GDSConfig(
        enabled=True,
        expose_as_tools=[GDSAlgorithm.SHORTEST_PATH, GDSAlgorithm.NODE_SIMILARITY],
        fallback_to_basic=True,
    )

    async with MemoryClient(settings) as client:
        # Create memory
        memory = Neo4jMicrosoftMemory(
            memory_client=client,
            session_id="shopping-session-1",
            user_id="user-123",
            gds_config=gds_config,
        )

        # Create chat client
        chat_client = AzureOpenAIResponsesClient(model="gpt-4")

        # Create memory tools bound to the memory instance
        tools = create_memory_tools(memory, include_gds_tools=True)

        # Create agent — tools are callable, framework auto-invokes them
        agent = chat_client.as_agent(
            name="ShoppingAssistant",
            instructions="""You are a helpful shopping assistant.
            Use memory tools to remember preferences and provide personalized recommendations.""",
            tools=tools,
            context_providers=[memory.context_provider],
        )

        # Conversation loop
        while True:
            user_input = input("You: ")
            if user_input.lower() in ("quit", "exit"):
                break

            # Save user message
            await memory.save_message("user", user_input)

            # Run agent — framework auto-invokes tools and returns final response
            response = await agent.run(Message("user", [user_input]))

            # Display response
            if response.text:
                await memory.save_message("assistant", response.text)
                print(f"Assistant: {response.text}")

            # Record trace for learning
            await record_agent_trace(
                memory=memory,
                messages=[
                    {"role": "user", "content": user_input},
                    {"role": "assistant", "content": response.text[:200] if response.text else ""},
                ],
                task=user_input,
                outcome="success",
                success=True,
            )


if __name__ == "__main__":
    asyncio.run(main())

API Compatibility

Target Version

This integration targets:

  • Package: agent-framework

  • Version: 1.0.0b260212

  • Status: Public Preview

  • GA Target: Q1 2026

Version Matrix

neo4j-agent-memory agent-framework Status

0.1.x

1.0.0b260212

Current

APIs Used

API Import Path

BaseContextProvider

agent_framework.BaseContextProvider

BaseHistoryProvider

agent_framework.BaseHistoryProvider

Message

agent_framework.Message

AzureOpenAIResponsesClient

agent_framework.azure.AzureOpenAIResponsesClient

Breaking Change Detection

Monitor for breaking changes:

  1. Check Microsoft Agent Framework release notes

  2. Run integration tests after upgrading

  3. Review API compatibility matrix in this documentation

Troubleshooting

ImportError: agent_framework not found

Install the Microsoft Agent Framework package:

pip install neo4j-agent-memory[microsoft-agent]
# or
pip install agent-framework>=1.0.0b

GDS Not Available Warning

If you see "GDS not available, using fallback":

  1. Install Neo4j GDS plugin on your database

  2. Or set fallback_to_basic=True (default) to use Cypher alternatives

  3. To silence: set warn_on_fallback=False

Empty Context

If get_context() returns empty:

  1. Verify embeddings are configured and generated

  2. Check that messages/entities exist in Neo4j

  3. Lower similarity_threshold (default: 0.7)

Serialization Errors

deserialize() requires a fresh MemoryClient:

# Wrong - connection not serializable
state = provider.serialize()
# ... save to file ...
provider = Neo4jContextProvider.deserialize(state)  # Missing client!

# Correct
state = provider.serialize()
# ... save to file ...
async with MemoryClient(settings) as client:  # Fresh client
    provider = Neo4jContextProvider.deserialize(state, memory_client=client)

API Reference

Neo4jContextProvider

Method Description

before_run(*, agent, session, context, state)

Called before agent invocation; injects memory context into SessionContext

after_run(*, agent, session, context, state)

Called after agent response; extracts and stores memories

serialize()

Serialize provider state

deserialize(state, memory_client)

Restore provider from state

Neo4jChatMessageStore

Method Description

add_messages(messages)

Add messages to conversation history

list_messages()

Get all messages for the session

clear()

Clear session messages

serialize()

Serialize store state

deserialize(serialized_state, memory_client)

Restore store from state

Neo4jMicrosoftMemory

Property/Method Description

context_provider

Get the underlying ContextProvider

chat_store

Get the underlying ChatMessageStore

gds

Get GDS integration (if enabled)

get_context(query)

Get combined context from all memory types

save_message(role, content)

Save a conversation message

search_memory(query)

Search across all memory types

add_preference(category, preference)

Add a user preference

find_entity_path(source, target)

Find path between entities

find_similar_entities(entity)

Find similar entities

get_important_entities()

Get entities ranked by importance

Functions

Function Description

create_memory_tools(memory, include_gds_tools=True)

Create callable FunctionTool instances bound to a memory instance. Tools are auto-invoked by the framework.

execute_memory_tool(…​) (deprecated)

Legacy manual tool dispatch. Use create_memory_tools() instead.

record_agent_trace(…​)

Record agent execution

get_similar_traces(…​)

Find similar past traces

format_traces_for_prompt(traces)

Format traces for prompts