`_inject_memories` had two paths that discarded memories without any
signal, so a misbehaving context looked identical to one with no
memories to inject.
The fallback branch only prepended a system message when `context.messages`
was a `list`, and silently did nothing otherwise. It also wrapped the insert
in `except Exception: pass`, commented "log a warning" but with nothing to
log through, since the function had no logger in scope.
The function now takes the middleware's logger and warns on both paths: one
for a non-list container, including the type it actually got, and one for an
insert that raised, including the exception type. Neither raises, since
injection is best-effort and must not fail the chat request.
`_inject_memories` is private with a single call site, so the logger is a
required argument rather than an optional one that could reintroduce the
silent path.
`_inject_memories` did not work against Agent Framework `Message`
objects, in two separate ways.
1. `Message.text` is a read-only property derived from `Message.contents`,
so assigning to it raises `AttributeError`. Every request that found an
existing system message hit this path, and `_inject_memories` is called
from `process()` without a guard, so the exception propagated and failed
the whole chat call. Memories are now appended as an extra text content
item, and the dict branch is checked first so plain-dict messages keep
working.
2. When no system message was present, the prepended message carried the
raw memories instead of the `wrap_memory_injection` output. That is the
fence which marks retrieved memories as data and tells the model not to
follow instructions inside them, so untrusted memory content reached the
model unfenced. This path is common, since it covers any agent built
without instructions. Both branches now inject the same wrapped text.
Adds coverage for `_inject_memories`, which previously had none.
## Summary
This PR introduces comprehensive Supermemory integration for the Microsoft Agent Framework, providing three complementary approaches to add persistent memory capabilities to agents: middleware for automatic memory injection, context providers for session-based memory management, and tools for explicit memory operations.
## Key Changes
- **SupermemoryChatMiddleware**: Automatic memory injection middleware that fetches relevant memories from Supermemory before LLM calls and optionally saves conversations. Supports three modes:
- `"profile"`: Injects all static and dynamic profile memories
- `"query"`: Searches for memories relevant to the current user message
- `"full"`: Combines both profile and query modes
- **SupermemoryContextProvider**: Idiomatic context provider following the Agent Framework pattern (similar to built-in Mem0 integration). Integrates with the session pipeline via `before_run()` and `after_run()` hooks for automatic memory retrieval and storage.
- **SupermemoryTools**: FunctionTool-compatible tools that agents can use for explicit memory operations:
- `search_memories()`: Search for specific memories
- `add_memory()`: Add new memories
- `get_profile()`: Retrieve user profile
- **Utility Functions**: Helper functions for:
- Memory deduplication across static, dynamic, and search result sources
- Profile-to-markdown conversion for LLM consumption
- Message extraction and conversation formatting
- Logging with configurable verbosity
- **Exception Hierarchy**: Custom exceptions for better error handling:
- `SupermemoryConfigurationError`: Missing/invalid configuration
- `SupermemoryAPIError`: API request failures
- `SupermemoryNetworkError`: Network connectivity issues
- `SupermemoryMemoryOperationError`: Memory operation failures
- **Comprehensive Documentation**: README with quick start examples, configuration options, and API reference for all three integration approaches.
- **Test Suite**: Unit tests covering middleware, context provider, tools, and utility functions with proper mocking and error scenarios.
## Implementation Details
- Supports both async (aiohttp) and sync (requests) HTTP clients with automatic fallback
- Handles multiple message formats (dict, objects with attributes, content arrays)
- Configurable memory storage with optional conversation grouping via `conversation_id`
- Environment variable fallback for API key configuration (`SUPERMEMORY_API_KEY`)
- Background task management for non-blocking memory operations in middleware
- Proper async/sync compatibility for the Supermemory SDK
https://claude.ai/code/session_012idB5y6UGK3zmeFULgTc4z