maximem-synap-deepagents 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: maximem-synap-deepagents
3
+ Version: 0.1.1
4
+ Summary: Synap memory integration for deepagents — a memory backend, retrieval middleware, and tools
5
+ Author: Synap Team
6
+ License-Expression: Apache-2.0
7
+ Keywords: synap,memory,deepagents,langchain,langgraph,ai,agents
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: maximem-synap>=0.2.0
11
+ Requires-Dist: maximem-synap-integrations-common>=0.1.0
12
+ Requires-Dist: deepagents>=0.7.4
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=7.0; extra == "dev"
15
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
16
+
17
+ # synap-deepagents
18
+
19
+ Synap integration for [deepagents](https://docs.langchain.com/oss/python/deepagents/overview) — LangChain's agent harness.
20
+
21
+ deepagents stores memory as `AGENTS.md` files and pastes them whole into the system prompt. This package plugs Synap in underneath, and adds a retrieval path the stock middleware cannot express.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install maximem-synap-deepagents
27
+ ```
28
+
29
+ Requires `deepagents>=0.7.4`, `maximem-synap>=0.2.0`.
30
+
31
+ ## Quickstart
32
+
33
+ Mount Synap on a route with `CompositeBackend`:
34
+
35
+ ```python
36
+ from deepagents import create_deep_agent
37
+ from deepagents.backends import CompositeBackend
38
+ from deepagents.backends.filesystem import FilesystemBackend
39
+ from maximem_synap import MaximemSynapSDK
40
+ from synap_deepagents import SynapBackend
41
+
42
+ sdk = MaximemSynapSDK(api_key="sk-...")
43
+
44
+ backend = CompositeBackend(
45
+ default=FilesystemBackend(root_dir="/path/to/repo"),
46
+ routes={"/memories/": SynapBackend(sdk, user_id="alice")},
47
+ )
48
+
49
+ agent = create_deep_agent(
50
+ model="anthropic:claude-sonnet-5",
51
+ backend=backend,
52
+ memory=["/memories/AGENTS.md"],
53
+ )
54
+
55
+ agent.invoke({"messages": [{"role": "user", "content": "What do I prefer?"}]})
56
+ ```
57
+
58
+ > **Mount it on a route, never as `backend=` on its own.** `SynapBackend` as the
59
+ > default backend would route the agent's source-code reads and writes through a
60
+ > memory API, and the agent would lose its working tree. The constructor cannot
61
+ > stop you.
62
+
63
+ ## The three surfaces
64
+
65
+ | Surface | Class | Use when |
66
+ |---|---|---|
67
+ | Backend | `SynapBackend` | You want memory to reach the agent through its own `read_file` / `grep` / `write_file` tools |
68
+ | Middleware | `SynapMemoryMiddleware` | You want recall scoped to the user's actual question |
69
+ | Tools | `SynapSearchTool`, `SynapStoreTool` | You want the model to reach for memory deliberately |
70
+
71
+ They compose. A common setup is the backend for automatic recall plus the tools for deliberate lookups.
72
+
73
+ ## `grep` is a semantic search
74
+
75
+ This is the part worth knowing. On a Synap route, the agent's `grep` tool is **not** a regex match over file bytes — the pattern is passed to Synap as a natural-language query:
76
+
77
+ ```python
78
+ # The agent runs this:
79
+ grep("what deployment process does the user follow", path="/memories/")
80
+ # It becomes this:
81
+ sdk.fetch(search_query=["what deployment process does the user follow"], mode="accurate")
82
+ ```
83
+
84
+ Stock deepagents `grep` can only find what is literally written in a file. This finds what the user said, however they said it. Matches are attributed to `/memories/AGENTS.md` so the agent can read the file for more.
85
+
86
+ Tell your agent about this in its system prompt if it tends to write regexes. A model assuming literal matching will write `^prefer.*` and misread the misses.
87
+
88
+ ## Query-conditioned recall
89
+
90
+ `create_deep_agent(memory=[...])` installs deepagents' own `MemoryMiddleware`, which calls `backend.download_files(paths)` — paths, no query. Even with `SynapBackend` underneath, that is one unqueried digest per run.
91
+
92
+ `SynapMemoryMiddleware` reads the pending user message first and passes it as the search query:
93
+
94
+ ```python
95
+ from synap_deepagents import SynapMemoryMiddleware
96
+
97
+ agent = create_deep_agent(
98
+ model="anthropic:claude-sonnet-5",
99
+ middleware=[SynapMemoryMiddleware(sdk=sdk, user_id="alice")],
100
+ )
101
+ ```
102
+
103
+ Use `memory=[...]` **or** `SynapMemoryMiddleware`, not both — they write to the same part of the system prompt, and you would pay for two retrievals to say the same thing twice.
104
+
105
+ ## Short-term context
106
+
107
+ Long-term memory and short-term context are different things. Short-term is the compacted history of the *current* conversation:
108
+
109
+ ```python
110
+ from synap_deepagents import synap_st_instructions
111
+
112
+ system_prompt = await synap_st_instructions(
113
+ sdk, "conv_abc", system="You are a helpful coding agent."
114
+ )
115
+ agent = create_deep_agent(model="...", system_prompt=system_prompt)
116
+ ```
117
+
118
+ That is a snapshot taken once. For a long-running agent, use `SynapShortTermMiddleware` instead, which refreshes each turn.
119
+
120
+ ## Error policy
121
+
122
+ | Operation | Behaviour |
123
+ |---|---|
124
+ | Reads (`read`, `grep`, `ls`, `glob`, `download_files`) | Degrade — log at `ERROR`, return empty or `file_not_found` |
125
+ | Writes (`write`, `edit`, `upload_files`) | Raise `SynapIntegrationError` |
126
+ | Recall in middleware | Degrades to an empty block — a Synap outage must not end the run |
127
+ | `delete` | **Not implemented** — see below |
128
+
129
+ Read failures are always reported as `file_not_found`, never any other code. That is deliberate: deepagents' `MemoryMiddleware` raises `ValueError` on any download error code *except* `file_not_found`, so returning anything else during a Synap outage would end the agent run instead of degrading to an empty memory block.
130
+
131
+ ## Why there is no `delete`
132
+
133
+ `sdk.memories.create()` returns an `ingestion_id`; `sdk.memories.delete()` needs a `memory_id`. They are different identifiers, and the memory does not exist yet at write time — ingestion is queued. So a path written through this backend cannot be resolved back to a durable memory, and a path-addressed delete cannot be honoured.
134
+
135
+ `delete` is optional in `BackendProtocol`, so this backend inherits the default that raises `NotImplementedError`, and `CompositeBackend` reports it cleanly. Remove memories through the Synap API or dashboard with a memory id.
136
+
137
+ ## Queued writes and read-after-write
138
+
139
+ Synap ingestion is asynchronous: `create` returns `{ingestion_id, document_id, status: QUEUED}`. A memory written a moment ago is not yet retrievable, so an agent that writes a file and reads it back in the same turn would get nothing — which reads as data loss.
140
+
141
+ `SynapBackend` keeps a short-TTL, per-process write-through cache so your own writes are always readable back. It is a read-after-write guarantee, **not** semantic dedup, and it does not survive a restart. Set `cache_ttl_seconds=0` to disable it only if you can tolerate that.
142
+
143
+ The package never polls `wait_for_completion` on the agent's path. Waiting would cost turn latency without improving the answer — Synap may split one submitted document into several memories or merge it with existing ones, so there is no count to wait for.
144
+
145
+ ## Configuration
146
+
147
+ ```python
148
+ SynapBackend(
149
+ sdk,
150
+ user_id="alice", # at least one of user_id / customer_id required
151
+ customer_id="acme",
152
+ conversation_id=None,
153
+ recall_filename="AGENTS.md", # basename that maps to the synthesized recall doc
154
+ max_results=20,
155
+ mode="fast", # retrieval mode for reads (on the startup path)
156
+ grep_mode="accurate", # retrieval mode for grep (a deliberate question)
157
+ precision_level="high",
158
+ document_type="document", # writes are explicit intent, not chat transcript
159
+ ingest_mode="fast",
160
+ include_conversation_context=False,
161
+ cache_ttl_seconds=300,
162
+ )
163
+ ```
164
+
165
+ ## Tests
166
+
167
+ ```bash
168
+ pytest integrations/synap-deepagents/tests -q
169
+ ```
@@ -0,0 +1,153 @@
1
+ # synap-deepagents
2
+
3
+ Synap integration for [deepagents](https://docs.langchain.com/oss/python/deepagents/overview) — LangChain's agent harness.
4
+
5
+ deepagents stores memory as `AGENTS.md` files and pastes them whole into the system prompt. This package plugs Synap in underneath, and adds a retrieval path the stock middleware cannot express.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pip install maximem-synap-deepagents
11
+ ```
12
+
13
+ Requires `deepagents>=0.7.4`, `maximem-synap>=0.2.0`.
14
+
15
+ ## Quickstart
16
+
17
+ Mount Synap on a route with `CompositeBackend`:
18
+
19
+ ```python
20
+ from deepagents import create_deep_agent
21
+ from deepagents.backends import CompositeBackend
22
+ from deepagents.backends.filesystem import FilesystemBackend
23
+ from maximem_synap import MaximemSynapSDK
24
+ from synap_deepagents import SynapBackend
25
+
26
+ sdk = MaximemSynapSDK(api_key="sk-...")
27
+
28
+ backend = CompositeBackend(
29
+ default=FilesystemBackend(root_dir="/path/to/repo"),
30
+ routes={"/memories/": SynapBackend(sdk, user_id="alice")},
31
+ )
32
+
33
+ agent = create_deep_agent(
34
+ model="anthropic:claude-sonnet-5",
35
+ backend=backend,
36
+ memory=["/memories/AGENTS.md"],
37
+ )
38
+
39
+ agent.invoke({"messages": [{"role": "user", "content": "What do I prefer?"}]})
40
+ ```
41
+
42
+ > **Mount it on a route, never as `backend=` on its own.** `SynapBackend` as the
43
+ > default backend would route the agent's source-code reads and writes through a
44
+ > memory API, and the agent would lose its working tree. The constructor cannot
45
+ > stop you.
46
+
47
+ ## The three surfaces
48
+
49
+ | Surface | Class | Use when |
50
+ |---|---|---|
51
+ | Backend | `SynapBackend` | You want memory to reach the agent through its own `read_file` / `grep` / `write_file` tools |
52
+ | Middleware | `SynapMemoryMiddleware` | You want recall scoped to the user's actual question |
53
+ | Tools | `SynapSearchTool`, `SynapStoreTool` | You want the model to reach for memory deliberately |
54
+
55
+ They compose. A common setup is the backend for automatic recall plus the tools for deliberate lookups.
56
+
57
+ ## `grep` is a semantic search
58
+
59
+ This is the part worth knowing. On a Synap route, the agent's `grep` tool is **not** a regex match over file bytes — the pattern is passed to Synap as a natural-language query:
60
+
61
+ ```python
62
+ # The agent runs this:
63
+ grep("what deployment process does the user follow", path="/memories/")
64
+ # It becomes this:
65
+ sdk.fetch(search_query=["what deployment process does the user follow"], mode="accurate")
66
+ ```
67
+
68
+ Stock deepagents `grep` can only find what is literally written in a file. This finds what the user said, however they said it. Matches are attributed to `/memories/AGENTS.md` so the agent can read the file for more.
69
+
70
+ Tell your agent about this in its system prompt if it tends to write regexes. A model assuming literal matching will write `^prefer.*` and misread the misses.
71
+
72
+ ## Query-conditioned recall
73
+
74
+ `create_deep_agent(memory=[...])` installs deepagents' own `MemoryMiddleware`, which calls `backend.download_files(paths)` — paths, no query. Even with `SynapBackend` underneath, that is one unqueried digest per run.
75
+
76
+ `SynapMemoryMiddleware` reads the pending user message first and passes it as the search query:
77
+
78
+ ```python
79
+ from synap_deepagents import SynapMemoryMiddleware
80
+
81
+ agent = create_deep_agent(
82
+ model="anthropic:claude-sonnet-5",
83
+ middleware=[SynapMemoryMiddleware(sdk=sdk, user_id="alice")],
84
+ )
85
+ ```
86
+
87
+ Use `memory=[...]` **or** `SynapMemoryMiddleware`, not both — they write to the same part of the system prompt, and you would pay for two retrievals to say the same thing twice.
88
+
89
+ ## Short-term context
90
+
91
+ Long-term memory and short-term context are different things. Short-term is the compacted history of the *current* conversation:
92
+
93
+ ```python
94
+ from synap_deepagents import synap_st_instructions
95
+
96
+ system_prompt = await synap_st_instructions(
97
+ sdk, "conv_abc", system="You are a helpful coding agent."
98
+ )
99
+ agent = create_deep_agent(model="...", system_prompt=system_prompt)
100
+ ```
101
+
102
+ That is a snapshot taken once. For a long-running agent, use `SynapShortTermMiddleware` instead, which refreshes each turn.
103
+
104
+ ## Error policy
105
+
106
+ | Operation | Behaviour |
107
+ |---|---|
108
+ | Reads (`read`, `grep`, `ls`, `glob`, `download_files`) | Degrade — log at `ERROR`, return empty or `file_not_found` |
109
+ | Writes (`write`, `edit`, `upload_files`) | Raise `SynapIntegrationError` |
110
+ | Recall in middleware | Degrades to an empty block — a Synap outage must not end the run |
111
+ | `delete` | **Not implemented** — see below |
112
+
113
+ Read failures are always reported as `file_not_found`, never any other code. That is deliberate: deepagents' `MemoryMiddleware` raises `ValueError` on any download error code *except* `file_not_found`, so returning anything else during a Synap outage would end the agent run instead of degrading to an empty memory block.
114
+
115
+ ## Why there is no `delete`
116
+
117
+ `sdk.memories.create()` returns an `ingestion_id`; `sdk.memories.delete()` needs a `memory_id`. They are different identifiers, and the memory does not exist yet at write time — ingestion is queued. So a path written through this backend cannot be resolved back to a durable memory, and a path-addressed delete cannot be honoured.
118
+
119
+ `delete` is optional in `BackendProtocol`, so this backend inherits the default that raises `NotImplementedError`, and `CompositeBackend` reports it cleanly. Remove memories through the Synap API or dashboard with a memory id.
120
+
121
+ ## Queued writes and read-after-write
122
+
123
+ Synap ingestion is asynchronous: `create` returns `{ingestion_id, document_id, status: QUEUED}`. A memory written a moment ago is not yet retrievable, so an agent that writes a file and reads it back in the same turn would get nothing — which reads as data loss.
124
+
125
+ `SynapBackend` keeps a short-TTL, per-process write-through cache so your own writes are always readable back. It is a read-after-write guarantee, **not** semantic dedup, and it does not survive a restart. Set `cache_ttl_seconds=0` to disable it only if you can tolerate that.
126
+
127
+ The package never polls `wait_for_completion` on the agent's path. Waiting would cost turn latency without improving the answer — Synap may split one submitted document into several memories or merge it with existing ones, so there is no count to wait for.
128
+
129
+ ## Configuration
130
+
131
+ ```python
132
+ SynapBackend(
133
+ sdk,
134
+ user_id="alice", # at least one of user_id / customer_id required
135
+ customer_id="acme",
136
+ conversation_id=None,
137
+ recall_filename="AGENTS.md", # basename that maps to the synthesized recall doc
138
+ max_results=20,
139
+ mode="fast", # retrieval mode for reads (on the startup path)
140
+ grep_mode="accurate", # retrieval mode for grep (a deliberate question)
141
+ precision_level="high",
142
+ document_type="document", # writes are explicit intent, not chat transcript
143
+ ingest_mode="fast",
144
+ include_conversation_context=False,
145
+ cache_ttl_seconds=300,
146
+ )
147
+ ```
148
+
149
+ ## Tests
150
+
151
+ ```bash
152
+ pytest integrations/synap-deepagents/tests -q
153
+ ```
@@ -0,0 +1,169 @@
1
+ Metadata-Version: 2.4
2
+ Name: maximem-synap-deepagents
3
+ Version: 0.1.1
4
+ Summary: Synap memory integration for deepagents — a memory backend, retrieval middleware, and tools
5
+ Author: Synap Team
6
+ License-Expression: Apache-2.0
7
+ Keywords: synap,memory,deepagents,langchain,langgraph,ai,agents
8
+ Requires-Python: >=3.11
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: maximem-synap>=0.2.0
11
+ Requires-Dist: maximem-synap-integrations-common>=0.1.0
12
+ Requires-Dist: deepagents>=0.7.4
13
+ Provides-Extra: dev
14
+ Requires-Dist: pytest>=7.0; extra == "dev"
15
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
16
+
17
+ # synap-deepagents
18
+
19
+ Synap integration for [deepagents](https://docs.langchain.com/oss/python/deepagents/overview) — LangChain's agent harness.
20
+
21
+ deepagents stores memory as `AGENTS.md` files and pastes them whole into the system prompt. This package plugs Synap in underneath, and adds a retrieval path the stock middleware cannot express.
22
+
23
+ ## Install
24
+
25
+ ```bash
26
+ pip install maximem-synap-deepagents
27
+ ```
28
+
29
+ Requires `deepagents>=0.7.4`, `maximem-synap>=0.2.0`.
30
+
31
+ ## Quickstart
32
+
33
+ Mount Synap on a route with `CompositeBackend`:
34
+
35
+ ```python
36
+ from deepagents import create_deep_agent
37
+ from deepagents.backends import CompositeBackend
38
+ from deepagents.backends.filesystem import FilesystemBackend
39
+ from maximem_synap import MaximemSynapSDK
40
+ from synap_deepagents import SynapBackend
41
+
42
+ sdk = MaximemSynapSDK(api_key="sk-...")
43
+
44
+ backend = CompositeBackend(
45
+ default=FilesystemBackend(root_dir="/path/to/repo"),
46
+ routes={"/memories/": SynapBackend(sdk, user_id="alice")},
47
+ )
48
+
49
+ agent = create_deep_agent(
50
+ model="anthropic:claude-sonnet-5",
51
+ backend=backend,
52
+ memory=["/memories/AGENTS.md"],
53
+ )
54
+
55
+ agent.invoke({"messages": [{"role": "user", "content": "What do I prefer?"}]})
56
+ ```
57
+
58
+ > **Mount it on a route, never as `backend=` on its own.** `SynapBackend` as the
59
+ > default backend would route the agent's source-code reads and writes through a
60
+ > memory API, and the agent would lose its working tree. The constructor cannot
61
+ > stop you.
62
+
63
+ ## The three surfaces
64
+
65
+ | Surface | Class | Use when |
66
+ |---|---|---|
67
+ | Backend | `SynapBackend` | You want memory to reach the agent through its own `read_file` / `grep` / `write_file` tools |
68
+ | Middleware | `SynapMemoryMiddleware` | You want recall scoped to the user's actual question |
69
+ | Tools | `SynapSearchTool`, `SynapStoreTool` | You want the model to reach for memory deliberately |
70
+
71
+ They compose. A common setup is the backend for automatic recall plus the tools for deliberate lookups.
72
+
73
+ ## `grep` is a semantic search
74
+
75
+ This is the part worth knowing. On a Synap route, the agent's `grep` tool is **not** a regex match over file bytes — the pattern is passed to Synap as a natural-language query:
76
+
77
+ ```python
78
+ # The agent runs this:
79
+ grep("what deployment process does the user follow", path="/memories/")
80
+ # It becomes this:
81
+ sdk.fetch(search_query=["what deployment process does the user follow"], mode="accurate")
82
+ ```
83
+
84
+ Stock deepagents `grep` can only find what is literally written in a file. This finds what the user said, however they said it. Matches are attributed to `/memories/AGENTS.md` so the agent can read the file for more.
85
+
86
+ Tell your agent about this in its system prompt if it tends to write regexes. A model assuming literal matching will write `^prefer.*` and misread the misses.
87
+
88
+ ## Query-conditioned recall
89
+
90
+ `create_deep_agent(memory=[...])` installs deepagents' own `MemoryMiddleware`, which calls `backend.download_files(paths)` — paths, no query. Even with `SynapBackend` underneath, that is one unqueried digest per run.
91
+
92
+ `SynapMemoryMiddleware` reads the pending user message first and passes it as the search query:
93
+
94
+ ```python
95
+ from synap_deepagents import SynapMemoryMiddleware
96
+
97
+ agent = create_deep_agent(
98
+ model="anthropic:claude-sonnet-5",
99
+ middleware=[SynapMemoryMiddleware(sdk=sdk, user_id="alice")],
100
+ )
101
+ ```
102
+
103
+ Use `memory=[...]` **or** `SynapMemoryMiddleware`, not both — they write to the same part of the system prompt, and you would pay for two retrievals to say the same thing twice.
104
+
105
+ ## Short-term context
106
+
107
+ Long-term memory and short-term context are different things. Short-term is the compacted history of the *current* conversation:
108
+
109
+ ```python
110
+ from synap_deepagents import synap_st_instructions
111
+
112
+ system_prompt = await synap_st_instructions(
113
+ sdk, "conv_abc", system="You are a helpful coding agent."
114
+ )
115
+ agent = create_deep_agent(model="...", system_prompt=system_prompt)
116
+ ```
117
+
118
+ That is a snapshot taken once. For a long-running agent, use `SynapShortTermMiddleware` instead, which refreshes each turn.
119
+
120
+ ## Error policy
121
+
122
+ | Operation | Behaviour |
123
+ |---|---|
124
+ | Reads (`read`, `grep`, `ls`, `glob`, `download_files`) | Degrade — log at `ERROR`, return empty or `file_not_found` |
125
+ | Writes (`write`, `edit`, `upload_files`) | Raise `SynapIntegrationError` |
126
+ | Recall in middleware | Degrades to an empty block — a Synap outage must not end the run |
127
+ | `delete` | **Not implemented** — see below |
128
+
129
+ Read failures are always reported as `file_not_found`, never any other code. That is deliberate: deepagents' `MemoryMiddleware` raises `ValueError` on any download error code *except* `file_not_found`, so returning anything else during a Synap outage would end the agent run instead of degrading to an empty memory block.
130
+
131
+ ## Why there is no `delete`
132
+
133
+ `sdk.memories.create()` returns an `ingestion_id`; `sdk.memories.delete()` needs a `memory_id`. They are different identifiers, and the memory does not exist yet at write time — ingestion is queued. So a path written through this backend cannot be resolved back to a durable memory, and a path-addressed delete cannot be honoured.
134
+
135
+ `delete` is optional in `BackendProtocol`, so this backend inherits the default that raises `NotImplementedError`, and `CompositeBackend` reports it cleanly. Remove memories through the Synap API or dashboard with a memory id.
136
+
137
+ ## Queued writes and read-after-write
138
+
139
+ Synap ingestion is asynchronous: `create` returns `{ingestion_id, document_id, status: QUEUED}`. A memory written a moment ago is not yet retrievable, so an agent that writes a file and reads it back in the same turn would get nothing — which reads as data loss.
140
+
141
+ `SynapBackend` keeps a short-TTL, per-process write-through cache so your own writes are always readable back. It is a read-after-write guarantee, **not** semantic dedup, and it does not survive a restart. Set `cache_ttl_seconds=0` to disable it only if you can tolerate that.
142
+
143
+ The package never polls `wait_for_completion` on the agent's path. Waiting would cost turn latency without improving the answer — Synap may split one submitted document into several memories or merge it with existing ones, so there is no count to wait for.
144
+
145
+ ## Configuration
146
+
147
+ ```python
148
+ SynapBackend(
149
+ sdk,
150
+ user_id="alice", # at least one of user_id / customer_id required
151
+ customer_id="acme",
152
+ conversation_id=None,
153
+ recall_filename="AGENTS.md", # basename that maps to the synthesized recall doc
154
+ max_results=20,
155
+ mode="fast", # retrieval mode for reads (on the startup path)
156
+ grep_mode="accurate", # retrieval mode for grep (a deliberate question)
157
+ precision_level="high",
158
+ document_type="document", # writes are explicit intent, not chat transcript
159
+ ingest_mode="fast",
160
+ include_conversation_context=False,
161
+ cache_ttl_seconds=300,
162
+ )
163
+ ```
164
+
165
+ ## Tests
166
+
167
+ ```bash
168
+ pytest integrations/synap-deepagents/tests -q
169
+ ```
@@ -0,0 +1,17 @@
1
+ README.md
2
+ pyproject.toml
3
+ maximem_synap_deepagents.egg-info/PKG-INFO
4
+ maximem_synap_deepagents.egg-info/SOURCES.txt
5
+ maximem_synap_deepagents.egg-info/dependency_links.txt
6
+ maximem_synap_deepagents.egg-info/requires.txt
7
+ maximem_synap_deepagents.egg-info/top_level.txt
8
+ synap_deepagents/__init__.py
9
+ synap_deepagents/backend.py
10
+ synap_deepagents/middleware.py
11
+ synap_deepagents/short_term.py
12
+ synap_deepagents/tools.py
13
+ tests/test_backend.py
14
+ tests/test_middleware.py
15
+ tests/test_public_surface.py
16
+ tests/test_short_term.py
17
+ tests/test_tools.py
@@ -0,0 +1,7 @@
1
+ maximem-synap>=0.2.0
2
+ maximem-synap-integrations-common>=0.1.0
3
+ deepagents>=0.7.4
4
+
5
+ [dev]
6
+ pytest>=7.0
7
+ pytest-asyncio>=0.21
@@ -0,0 +1,35 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "maximem-synap-deepagents"
7
+ version = "0.1.1"
8
+ description = "Synap memory integration for deepagents — a memory backend, retrieval middleware, and tools"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "Apache-2.0"
12
+ authors = [
13
+ {name = "Synap Team"}
14
+ ]
15
+ keywords = ["synap", "memory", "deepagents", "langchain", "langgraph", "ai", "agents"]
16
+
17
+ dependencies = [
18
+ "maximem-synap>=0.2.0",
19
+ "maximem-synap-integrations-common>=0.1.0",
20
+ "deepagents>=0.7.4",
21
+ ]
22
+
23
+ [project.optional-dependencies]
24
+ dev = [
25
+ "pytest>=7.0",
26
+ "pytest-asyncio>=0.21",
27
+ ]
28
+
29
+ [tool.setuptools.packages.find]
30
+ where = ["."]
31
+ include = ["synap_deepagents*"]
32
+
33
+ [tool.pytest.ini_options]
34
+ testpaths = ["tests"]
35
+ asyncio_mode = "auto"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,88 @@
1
+ """Synap memory integration for deepagents.
2
+
3
+ deepagents is LangChain's agent harness. It reaches storage through
4
+ ``BackendProtocol`` — a filesystem interface — and reaches memory through
5
+ ``MemoryMiddleware``, which pastes whole ``AGENTS.md`` files into the system
6
+ prompt. This package plugs Synap into both, and adds a retrieval path the stock
7
+ middleware cannot express.
8
+
9
+ Three surfaces, useful separately or together:
10
+
11
+ **1. A backend.** :class:`SynapBackend` implements ``BackendProtocol`` so the
12
+ agent's own ``read_file`` / ``grep`` / ``write_file`` tools reach Synap. Mount it
13
+ on a route — never as the default backend, or the agent loses its working tree::
14
+
15
+ from deepagents import create_deep_agent
16
+ from deepagents.backends import CompositeBackend, FilesystemBackend
17
+ from maximem_synap import MaximemSynapSDK
18
+ from synap_deepagents import SynapBackend
19
+
20
+ sdk = MaximemSynapSDK(api_key="sk-...")
21
+
22
+ backend = CompositeBackend(
23
+ default=FilesystemBackend(root_dir="/path/to/repo"),
24
+ routes={"/memories/": SynapBackend(sdk, user_id="alice")},
25
+ )
26
+
27
+ agent = create_deep_agent(
28
+ model="anthropic:claude-sonnet-5",
29
+ backend=backend,
30
+ memory=["/memories/AGENTS.md"],
31
+ )
32
+
33
+ Note what ``grep`` does here: on a Synap route it is a **semantic search**, not a
34
+ regex match. The agent asks a question in plain language and gets an answer.
35
+
36
+ **2. Middleware.** :class:`SynapMemoryMiddleware` retrieves memory using the
37
+ user's actual question as the search query, which ``MemoryMiddleware`` cannot do
38
+ — it only knows file paths. Use it instead of ``memory=[...]``, not alongside::
39
+
40
+ agent = create_deep_agent(
41
+ model="anthropic:claude-sonnet-5",
42
+ middleware=[SynapMemoryMiddleware(sdk=sdk, user_id="alice")],
43
+ )
44
+
45
+ :class:`SynapShortTermMiddleware` does the same for compacted conversation
46
+ history, refreshed each turn.
47
+
48
+ **3. Tools.** :class:`SynapSearchTool` and :class:`SynapStoreTool` are ordinary
49
+ LangChain tools, for when you want the model to reach for memory deliberately
50
+ rather than have it arrive automatically.
51
+
52
+ Error policy: reads degrade — a Synap outage yields an empty memory block and a
53
+ logged error, never a failed agent run. Writes raise ``SynapIntegrationError``.
54
+ There is no ``delete``: ``memories.create`` returns an ingestion id rather than a
55
+ memory id, so a path cannot be resolved back to a durable memory. Remove
56
+ memories through the Synap API with a memory id.
57
+ """
58
+
59
+ from synap_deepagents.backend import (
60
+ DEFAULT_CACHE_TTL_SECONDS,
61
+ DEFAULT_RECALL_FILENAME,
62
+ SynapBackend,
63
+ )
64
+ from synap_deepagents.middleware import (
65
+ SYNAP_MEMORY_PROMPT,
66
+ SynapMemoryMiddleware,
67
+ SynapShortTermMiddleware,
68
+ )
69
+ from synap_deepagents.short_term import (
70
+ compose_system_prompt,
71
+ fetch_st_block,
72
+ synap_st_instructions,
73
+ )
74
+ from synap_deepagents.tools import SynapSearchTool, SynapStoreTool
75
+
76
+ __all__ = [
77
+ "DEFAULT_CACHE_TTL_SECONDS",
78
+ "DEFAULT_RECALL_FILENAME",
79
+ "SYNAP_MEMORY_PROMPT",
80
+ "SynapBackend",
81
+ "SynapMemoryMiddleware",
82
+ "SynapSearchTool",
83
+ "SynapShortTermMiddleware",
84
+ "SynapStoreTool",
85
+ "compose_system_prompt",
86
+ "fetch_st_block",
87
+ "synap_st_instructions",
88
+ ]