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

# Semantic Kernel

> Kernel plugin with memory search and storage functions for Microsoft Semantic Kernel.

Add persistent, per-user memory to a Semantic Kernel application as a single plugin. Both kernel functions (`search_memory` and `store_memory`) are auto-invokable, so the kernel can decide when to query or persist memories on its own.

<Note>
  Requires Python 3.11+.
</Note>

## Overview

This guide shows how to add Synap to a Semantic Kernel application to build kernels that:

* Recall user-specific facts, preferences, and past conversations
* Persist new information surfaced during a conversation
* Auto-invoke memory functions when the model decides they are relevant

The Synap Semantic Kernel integration ships a single plugin class with two kernel functions.

| Export        | SK interface  | Purpose                                                      |
| ------------- | ------------- | ------------------------------------------------------------ |
| `SynapPlugin` | Kernel plugin | Provides `search_memory` and `store_memory` kernel functions |

## Setup

Install the package alongside Semantic Kernel:

<CodeGroup>
  ```bash pip theme={null}
  pip install maximem-synap-semantic-kernel semantic-kernel
  ```

  ```bash uv theme={null}
  uv add maximem-synap-semantic-kernel semantic-kernel
  # pip-compatible (existing venv): uv pip install maximem-synap-semantic-kernel semantic-kernel
  ```
</CodeGroup>

<Note>
  The pip package is `maximem-synap-semantic-kernel`, but the import drops the `maximem-` prefix and uses underscores: `from synap_semantic_kernel import ...`.
</Note>

Configure your API key. Generate one from the [Synap Dashboard](https://synap.maximem.ai).

```bash .env theme={null}
SYNAP_API_KEY=synap_your_key_here
OPENAI_API_KEY=your-openai-api-key
```

Initialize the SDK once at application startup:

```python theme={null}
from maximem_synap import MaximemSynapSDK

sdk = MaximemSynapSDK()
await sdk.initialize()
```

See [SDK Initialization](/sdk/initialization) for the full lifecycle and configuration options.

## Basic integration

The smallest useful integration adds `SynapPlugin` to a kernel and invokes a prompt that references the plugin's functions:

```python theme={null}
# pip install maximem-synap-semantic-kernel semantic-kernel
from maximem_synap import MaximemSynapSDK
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from synap_semantic_kernel import SynapPlugin

sdk = MaximemSynapSDK()
await sdk.initialize()

kernel = Kernel()
kernel.add_service(OpenAIChatCompletion(service_id="default"))

kernel.add_plugin(
    SynapPlugin(sdk=sdk, user_id="alice", customer_id="acme"),
    plugin_name="synap",
)

result = await kernel.invoke_prompt(
    "{{synap.search_memory query='project priorities'}} What are my top priorities?"
)
```

The scoping triple (`user_id`, optional `customer_id`) is bound when you construct the plugin. The kernel functions only ever see `query`, `content`, and other model-supplied parameters. This prevents prompts (or prompt injections) from spoofing scope.

For automatic invocation (the kernel chooses when to call memory functions), enable auto function calling. See "Auto function calling" below.

***

## Core concepts

### SynapPlugin

`SynapPlugin` is a regular Semantic Kernel plugin class with `@kernel_function` annotated methods. Adding it to the kernel registers both functions under the plugin name you choose:

```python theme={null}
from synap_semantic_kernel import SynapPlugin

plugin = SynapPlugin(
    sdk=sdk,
    user_id="alice",
    customer_id="acme",   # optional, required for B2B instances
)

kernel.add_plugin(plugin, plugin_name="synap")
```

After registration, the kernel can invoke `synap.search_memory` and `synap.store_memory` either through prompt templating, manual invocation, or auto function calling.

### search\_memory

Function signature exposed to the kernel:

```text theme={null}
search_memory(query: str, max_results: int = 5) -> str
```

Returns a formatted string of results, suitable for direct interpolation into prompt templates. **Search failures degrade gracefully**: the function returns an empty result string and logs an error so the prompt template renders without breaking.

### store\_memory

Function signature exposed to the kernel:

```text theme={null}
store_memory(content: str, memory_type: str = "fact") -> str
```

Returns `"Memory stored successfully."` on success. **Store failures surface explicitly**: the function raises `SynapIntegrationError` so the kernel (and caller) know if persistence failed.

***

## Complete example: chat function with auto-invoked memory

The following kernel auto-invokes `synap.search_memory` and `synap.store_memory` whenever the model decides they are relevant. The application just adds messages to a `ChatHistory` and the kernel handles the rest:

```python theme={null}
from semantic_kernel import Kernel
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
from semantic_kernel.contents import ChatHistory
from synap_semantic_kernel import SynapPlugin


def build_kernel(sdk, user_id: str, customer_id: str | None = None) -> Kernel:
    kernel = Kernel()
    kernel.add_service(OpenAIChatCompletion(service_id="default"))
    kernel.add_plugin(
        SynapPlugin(sdk=sdk, user_id=user_id, customer_id=customer_id),
        plugin_name="synap",
    )
    return kernel


async def chat(kernel: Kernel, history: ChatHistory, message: str) -> str:
    settings = kernel.get_prompt_execution_settings_from_service_id("default")
    settings.function_choice_behavior = FunctionChoiceBehavior.Auto()

    history.add_user_message(message)

    chat_service = kernel.get_service("default")
    response = await chat_service.get_chat_message_content(
        chat_history=history,
        settings=settings,
        kernel=kernel,
    )
    history.add_message(response)
    return str(response)


# Usage
kernel = build_kernel(sdk, user_id="alice", customer_id="acme")
history = ChatHistory(system_message=(
    "You are a personal assistant. Call synap.search_memory before answering "
    "questions about the user. Call synap.store_memory when they share a new fact."
))

await chat(kernel, history, "I just upgraded to the Pro plan.")
reply = await chat(kernel, history, "What plan am I on?")
# → "You're on the Pro plan."
```

Three things to notice in this pattern:

1. **`FunctionChoiceBehavior.Auto()` lets the model drive memory.** No prompt-template plumbing; the model calls the right function when it's the right time.
2. **Scope is per-kernel.** `build_kernel(...)` constructs a fresh kernel per user so concurrent requests cannot bleed scope.
3. **The system message is the policy.** Tell the model when to search and when to store; the plugin just enforces it.

***

## Advanced patterns

### Multi-tenant scoping

`SynapPlugin` accepts 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](/concepts/memory-scopes).

```python theme={null}
# User-scoped only
plugin = SynapPlugin(sdk=sdk, user_id="alice")

# Organization-scoped (user sees org-shared memories too)
plugin = SynapPlugin(sdk=sdk, user_id="alice", customer_id="acme-corp")
```

For multi-tenant services, build the plugin (and kernel) per request rather than sharing one across users.

### Prompt-template invocation

Outside of auto function calling, you can interpolate plugin calls directly in prompt templates:

```python theme={null}
result = await kernel.invoke_prompt(
    "Context: {{synap.search_memory query='dietary preferences'}}\n"
    "Question: What should I order for dinner?"
)
```

This pattern is useful when you want deterministic recall (the function *always* runs) rather than letting the model decide.

### Failure semantics

The integration follows the Synap-wide contract:

* **`search_memory` degrades gracefully**: returns an empty result string and logs an error if Synap is unreachable.
* **`store_memory` surfaces failures**: raises `SynapIntegrationError` so the kernel and caller know persistence failed.

This is by design: read failures shouldn't break a user-facing answer, but silent write failures would let the memory drift away from reality.

***

## Going further

* [Patterns overview](/patterns/overview): reusable memory patterns across frameworks.
* [Cookbook overview](/cookbook/overview): end-to-end worked examples.

***

## Next steps

<CardGroup cols={2}>
  <Card title="Microsoft Agent Framework" icon="microsoft" href="/integrations/microsoft-agent">
    Context and history providers for MAF agents.
  </Card>

  <Card title="OpenAI Agents" icon="robot" href="/integrations/openai-agents">
    Function tools for the OpenAI Agents SDK.
  </Card>

  <Card title="Context Fetch" icon="search" href="/sdk/context-fetch">
    The retrieval API behind `search_memory`: modes, scopes, and response shapes.
  </Card>

  <Card title="Memory Scopes" icon="layer-group" href="/concepts/memory-scopes">
    How `user_id` and `customer_id` interact across reads and writes.
  </Card>
</CardGroup>
