Skip to main content

synap-microsoft-agent

Synap memory integration for Microsoft Agent Framework (MAF).

Install

pip install synap-microsoft-agent

Requires agent-framework>=1.0, maximem-synap>=0.7.1.

Quickstart

from agent_framework import InMemoryHistoryProvider
from agent_framework.openai import OpenAIChatClient
from maximem_synap import MaximemSynapSDK
from synap_microsoft_agent import SynapContextProvider, SynapHistoryProvider

sdk = MaximemSynapSDK(api_key="sk-...")
client = OpenAIChatClient(model="gpt-4o-mini")

agent = client.as_agent(
    name="MemoryAgent",
    instructions="You are a helpful assistant.",
    context_providers=[
        SynapContextProvider(
            sdk=sdk,
            user_id="alice",
            customer_id="acme",
        ),
        SynapHistoryProvider(
            sdk=sdk,
            user_id="alice",
            customer_id="acme",
        ),
    ],
)

session = agent.create_session()
result = await agent.run("What's my trial expiring?", session=session)

What each provider does

  • SynapContextProvider: on every turn, fetches Synap context (facts, preferences, episodes, emotions, temporal events) and appends it as instructions. Records the user + assistant messages back to Synap, and reports the whole turn on the live stream (see below). This is the provider that owns the turn lifecycle. It also adds SynapCompactionMiddleware to every run: once Synap has compacted the conversation, the model sees Synap's compaction and the turns after it instead of the earlier turns your history provider (InMemoryHistoryProvider, Redis, Cosmos...) holds. Until then, or if Synap cannot answer, the messages are untouched; MAF's own compaction stays installed. It works wherever the history provider sits in the list.

  • SynapHistoryProvider: keeps the conversation log in Synap. Loads Synap's view on session resume (the compaction, then the turns after it). Subclass of MAF's HistoryProvider, so all its flags (load_messages, store_inputs, store_outputs, store_context_messages) work as documented. Next to SynapContextProvider each turn is still written once, by this provider.

  • SynapShortTermContextProvider: injects Synap's compaction of the current conversation into the instructions, refreshed each turn. It adds no recent turns: your history provider already sends them.

You can use either or both; they coexist.

The live stream

The first report opens sdk.instance.listen() if you have not, and this integration reports the whole turn on it (SYNAP_AUTO_LISTEN=false turns that off and the turns go over REST), so Synap's anticipation agent sees more than a question and an answer:

what happened event
the user spoke user_message, from before_run, before the retrieval it causes
the agent reasoned agent_thinking, from the text_reasoning contents MAF leaves off Message.text
the agent called a tool tool_call, from function middleware added to the invocation
the tool returned tool_result, under the same tool_call_id as the call
the agent answered assistant_message

Stream first, REST only as a fallback, never both. The server writes the conversation row from the stream event itself, so reporting a turn and calling record_message would store it twice and extract it twice. Each turn goes out on the stream if one is open and over REST if it is not.

Without a stream (auto-listen off, or it will not open) the user and assistant turns go over REST and the tool, reasoning and result reports are no-ops. No report can raise into your agent run.

A system message is not a turn and is not written: it has no stream event (report_turn would file it as something the assistant said) and record_message takes user or assistant only.

The Agent Harness

MAF's harness (create_harness_agent) is a separate surface with its own memory subsystem, and this package backs both of its storage seams. Needs agent-framework>=1.13; the classes import lazily so the floor above stays at 1.0.

from agent_framework import create_harness_agent
from synap_microsoft_agent import SynapAgentFileStore, create_synap_harness_memory

agent = create_harness_agent(
    client,
    history_provider=create_synap_harness_memory(sdk, user_id="alice", customer_id="acme"),
    file_memory_store=SynapAgentFileStore(sdk, user_id="alice", customer_id="acme"),
)
  • SynapMemoryStore — backs the topic notebook (MEMORY.md, topic records, extraction, consolidation). Extraction and consolidation stay MAF's; storage and retrieval become Synap's. MEMORY.md gains a durable recall block that survives restarts and is shared across agents on the same scope.
  • SynapAgentFileStore — backs the seven file_memory_* tools. grep searches by regex and by meaning; delete is real.
  • create_synap_harness_memory — builds the provider wired correctly. Prefer it.

Two things to know:

  1. create_harness_agent takes exactly one history_provider, and both SynapHistoryProvider and the harness memory provider are HistoryProviders. Passing both silently drops one. Use the factory and pass only that.
  2. Topic records are held exactly, and by default only for the life of the process. Synap's ingestion rewrites what you submit, and the harness does read-modify-write on records, so reading them back from Synap would corrupt them a little more each turn. Pass a record_store to survive restarts. The content is durable in Synap either way.

Every harness API is @experimental upstream. Pin a tested version and re-run the suite on each MAF minor.

Deeper scope ladders

On an account whose scope ladder has more levels than customer and user, pass the level as scope_path (level key to value) to SynapContextProvider, SynapHistoryProvider, SynapMemoryStore, SynapAgentFileStore or create_synap_harness_memory. It is sent with every fetch, write and turn the object makes, and only when set. It is fixed when the object is built; the store's tools take no level from the model.

path = {"customer": "acme", "team": "payments", "user": "alice"}
provider = SynapContextProvider(sdk, user_id="alice", customer_id="acme", scope_path=path)
memory = create_synap_harness_memory(sdk, user_id="alice", customer_id="acme", scope_path=path)

With a path, the store's owner label is built from the path values in the order given (/acme/payments/alice); the server orders levels by ladder position, so order does not matter to it, but the label is the store's local record partition key: the same levels in a different key order give a different label and a different local partition. A value must be a non-empty string without /; a bad path raises ValueError when the object is built. maximem_synap.ScopeLadder.address(values) builds user_id, customer_id and scope_path from level values. A path that includes user or customer fixes them: a user_id or customer_id that disagrees with it raises SynapIntegrationError when the object is built (the server would otherwise let the path win). Without scope_path nothing changes.

Needs a newer SDK. A path needs a maximem-synap release that has get_scope_ladder and scope_path on fetch, send_message and record_message (and scope on memories.create). With an older SDK, a turn that carries a path is dropped and an error is logged: it is never filed at a wider scope. Leave scope_path unset on an older SDK.

Error policy

  • Read-side failures (fetch, get_context_for_prompt) degrade gracefully — logged at ERROR, empty result returned. An outage never crashes an agent turn.
  • Write-side failures — SynapContextProvider.after_run logs and swallows (context providers must not raise per MAF's hook contract). SynapHistoryProvider.save_messages surfaces errors as SynapIntegrationError so explicit persistence failures are observable.
  • Stream reports never raise and never fall over into your agent run. A report that fails is a report that did not go out, so the turn takes the REST path instead. The one report that is logged at WARNING rather than debug is a refused tool-reporter install, because that costs every tool call and every tool result for the whole run.
  • Harness stores — same split. get_index_text degrades to pointer lines with no recall block, because it feeds the system prompt on every turn. write_topic and file_memory_write raise. A topic that is not held raises FileNotFoundError, which is MAF's own not-found contract.

Tests

pytest integrations/synap-microsoft-agent/tests -q

The harness tests skip cleanly when agent-framework<1.13 is installed, so the SDK surfaces stay testable on the floor version. bench/smoke.py drives MAF's real MemoryContextProvider and FileMemoryProvider over both stores — run it with --mock for no network, or with credentials and --scope against a seeded scope.

Metadata

Release files for maximem-synap-microsoft-agent 0.3.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for maximem-synap-microsoft-agent 0.3.4
File Size Uploaded Provenance Actions
maximem_synap_microsoft_agent-0.3.4.tar.gz 72.2 kB Without provenance Details for maximem_synap_microsoft_agent-0.3.4.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for maximem-synap-microsoft-agent 0.3.4
File Interpreter ABI Platform Actions
maximem_synap_microsoft_agent-0.3.4-py3-none-any.whl Python 3 none any Details for maximem_synap_microsoft_agent-0.3.4-py3-none-any.whl

Total release size: 121.6 kB

Release files / maximem_synap_microsoft_agent-0.3.4.tar.gz

Download URL maximem_synap_microsoft_agent-0.3.4.tar.gz
Size 72.2 kB
Tags Source
SHA-256 checksum
How to use checksums
cd56a7577cfefab87d43c517665dbd10fdcf64d7c751d0596ab36583f1430dfc
BLAKE2b-256 checksum
How to use checksums
4950002389673667d7af0df15511f5deaa44e95e2473788c19d9612472f737c3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.4

Release files / maximem_synap_microsoft_agent-0.3.4-py3-none-any.whl

Download URL maximem_synap_microsoft_agent-0.3.4-py3-none-any.whl
Size 49.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4252c4ed25a1e1f6eb862ef87a341f48019ff70b35f945dd1f32db561fc768db
BLAKE2b-256 checksum
How to use checksums
b4a040062ef428b59dbb3d66d80d9a32200226ba0a968314f24872f3275ae792
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.4

Security for maximem-synap-microsoft-agent 0.3.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page