@maximem/synap-js-sdk 0.1.1 → 0.1.4
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.
- package/README.md +41 -199
- package/bridge/synap_bridge.py +6 -3
- package/package.json +1 -1
- package/src/synap-client.js +15 -14
package/README.md
CHANGED
|
@@ -1,88 +1,52 @@
|
|
|
1
1
|
# @maximem/synap-js-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Node.js wrapper for the Synap Python SDK.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
## Prerequisites
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
- Node.js 18+
|
|
8
|
+
- Python 3.8+
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Architecture
|
|
10
|
+
## Install
|
|
12
11
|
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
-> @maximem/synap-js-sdk (JS API)
|
|
16
|
-
-> BridgeManager (JSON-RPC over stdin/stdout)
|
|
17
|
-
-> synap_bridge.py
|
|
18
|
-
-> maximem_synap (Python SDK)
|
|
19
|
-
-> Synap API + gRPC
|
|
12
|
+
```bash
|
|
13
|
+
npm install @maximem/synap-js-sdk
|
|
20
14
|
```
|
|
21
15
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
```text
|
|
25
|
-
[1] App calls createClient()/client.init()
|
|
26
|
-
->
|
|
27
|
-
[2] BridgeManager resolves python path + bridge path
|
|
28
|
-
-> FAIL A: python not found / bridge file missing
|
|
29
|
-
->
|
|
30
|
-
[3] Node spawns synap_bridge.py child process
|
|
31
|
-
-> FAIL B: process spawn/runtime error
|
|
32
|
-
->
|
|
33
|
-
[4] Node sends JSON-RPC "init"
|
|
34
|
-
->
|
|
35
|
-
[5] Python imports maximem_synap + builds SDK config
|
|
36
|
-
-> FAIL C: maximem_synap not installed in chosen python/venv
|
|
37
|
-
->
|
|
38
|
-
[6] SDK initialize() + optional gRPC listen
|
|
39
|
-
-> FAIL D: invalid instance/auth OR API/gRPC endpoint unreachable
|
|
40
|
-
->
|
|
41
|
-
[7] App calls add/search/get/delete
|
|
42
|
-
->
|
|
43
|
-
[8] Node sends JSON-RPC method
|
|
44
|
-
-> FAIL E: IPC timeout / broken pipe / bridge crash
|
|
45
|
-
->
|
|
46
|
-
[9] Python executes SDK operation
|
|
47
|
-
-> FAIL F: SDK/server error, bad input, ingestion timeout
|
|
48
|
-
->
|
|
49
|
-
[10] Python returns JSON result
|
|
50
|
-
->
|
|
51
|
-
[11] Node resolves promise and returns to app
|
|
52
|
-
```
|
|
16
|
+
## Setup (JS Runtime)
|
|
53
17
|
|
|
54
|
-
|
|
18
|
+
Install the Python runtime used by the wrapper:
|
|
55
19
|
|
|
56
|
-
|
|
20
|
+
```bash
|
|
21
|
+
npx synap-js-sdk setup --sdk-version 0.1.1
|
|
22
|
+
```
|
|
57
23
|
|
|
58
|
-
|
|
59
|
-
2. Python (for the bridge + Synap Python SDK)
|
|
60
|
-
3. A virtualenv containing `maximem-synap`
|
|
24
|
+
If you want the latest Python SDK version, omit `--sdk-version`.
|
|
61
25
|
|
|
62
|
-
|
|
26
|
+
## Verify Runtime
|
|
63
27
|
|
|
64
|
-
|
|
28
|
+
macOS/Linux:
|
|
65
29
|
|
|
66
30
|
```bash
|
|
67
|
-
|
|
31
|
+
~/.synap-js-sdk/.venv/bin/python -c "import maximem_synap; print(maximem_synap.__version__)"
|
|
68
32
|
```
|
|
69
33
|
|
|
70
|
-
|
|
34
|
+
Windows:
|
|
71
35
|
|
|
72
|
-
```
|
|
73
|
-
|
|
36
|
+
```powershell
|
|
37
|
+
$env:USERPROFILE\.synap-js-sdk\.venv\Scripts\python.exe -c "import maximem_synap; print(maximem_synap.__version__)"
|
|
74
38
|
```
|
|
75
39
|
|
|
76
|
-
|
|
77
|
-
This wrapper installs the Python SDK from package indexes (PyPI by default), not from local source paths.
|
|
40
|
+
## Required Environment Variables
|
|
78
41
|
|
|
79
|
-
|
|
42
|
+
- `SYNAP_INSTANCE_ID`
|
|
43
|
+
- `SYNAP_BOOTSTRAP_TOKEN` (required for first-time initialization/new instance)
|
|
44
|
+
- `SYNAP_BASE_URL`
|
|
45
|
+
- `SYNAP_GRPC_HOST`
|
|
46
|
+
- `SYNAP_GRPC_PORT`
|
|
47
|
+
- `SYNAP_GRPC_TLS`
|
|
80
48
|
|
|
81
|
-
|
|
82
|
-
npm install @maximem/synap-js-sdk && npx synap-js-sdk setup --sdk-version <PY_SDK_VERSION> && npx synap-js-sdk setup-ts
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Quick start in a Node project
|
|
49
|
+
## Quick Start (JavaScript)
|
|
86
50
|
|
|
87
51
|
```js
|
|
88
52
|
const { createClient } = require('@maximem/synap-js-sdk');
|
|
@@ -101,10 +65,7 @@ async function run() {
|
|
|
101
65
|
|
|
102
66
|
await synap.addMemory({
|
|
103
67
|
userId: 'user-123',
|
|
104
|
-
messages: [
|
|
105
|
-
{ role: 'user', content: 'My name is Alex and I live in Austin.' },
|
|
106
|
-
{ role: 'assistant', content: 'Got it.' },
|
|
107
|
-
],
|
|
68
|
+
messages: [{ role: 'user', content: 'My name is Alex and I live in Austin.' }],
|
|
108
69
|
});
|
|
109
70
|
|
|
110
71
|
const result = await synap.searchMemory({
|
|
@@ -120,147 +81,28 @@ async function run() {
|
|
|
120
81
|
run().catch(console.error);
|
|
121
82
|
```
|
|
122
83
|
|
|
123
|
-
##
|
|
124
|
-
|
|
125
|
-
### `createClient(options)` / `new SynapClient(options)`
|
|
84
|
+
## TypeScript Extension Setup
|
|
126
85
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
- `instanceId`: explicit Synap instance id. If omitted, the SDK tries `SYNAP_INSTANCE_ID`, then `~/.synap/instances/*/metadata.json`.
|
|
130
|
-
- `bootstrapToken`: one-time bootstrap token/key (env: `SYNAP_BOOTSTRAP_TOKEN` or `SYNAP_BOOTSTRAP_KEY`). Required on first initialization of a new instance.
|
|
131
|
-
- `baseUrl`, `grpcHost`, `grpcPort`, `grpcUseTls`: Synap endpoints.
|
|
132
|
-
- `pythonBin`: explicit Python path for the bridge.
|
|
133
|
-
- `bridgeScriptPath`: override Python bridge script path.
|
|
134
|
-
- `sdkHome`: home for managed runtime (default `~/.synap-js-sdk`).
|
|
135
|
-
- `venvPath`: override managed venv path.
|
|
136
|
-
- `pythonPackage`: pip package name (default `maximem-synap`).
|
|
137
|
-
- `pythonSdkVersion`: pip version pin.
|
|
138
|
-
- `noDeps`: use pip `--no-deps` during auto setup.
|
|
139
|
-
- `noBuildIsolation`: use pip `--no-build-isolation` during auto setup.
|
|
140
|
-
- `upgrade`: use pip `--upgrade` during auto setup.
|
|
141
|
-
- `forceRecreateVenv`: recreate managed venv during auto setup.
|
|
142
|
-
- `autoSetup`: if `true`, runtime setup is attempted automatically when Python is missing.
|
|
143
|
-
|
|
144
|
-
### Methods
|
|
145
|
-
|
|
146
|
-
- `init()`
|
|
147
|
-
- `addMemory({ userId, messages })`
|
|
148
|
-
- `searchMemory({ userId, query, maxResults })`
|
|
149
|
-
- `getMemories({ userId })`
|
|
150
|
-
- `deleteMemory({ userId, memoryId })`
|
|
151
|
-
- `shutdown()`
|
|
152
|
-
|
|
153
|
-
## CLI
|
|
86
|
+
Add TypeScript support to an existing JS project:
|
|
154
87
|
|
|
155
88
|
```bash
|
|
156
|
-
synap-js-sdk setup
|
|
157
|
-
synap-js-sdk setup-ts [options]
|
|
89
|
+
npx synap-js-sdk setup-ts
|
|
158
90
|
```
|
|
159
91
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
`
|
|
163
|
-
-
|
|
164
|
-
- `--sdk-home <path>`: runtime home directory
|
|
165
|
-
- `--venv <path>`: virtualenv path
|
|
166
|
-
- `--package <name>`: Python package name
|
|
167
|
-
- `--sdk-version <ver>`: Python SDK version pin
|
|
168
|
-
- `--no-deps`: install package with no dependency resolution
|
|
169
|
-
- `--no-build-isolation`: disable pip build isolation
|
|
170
|
-
- `--upgrade`: use pip `--upgrade`
|
|
171
|
-
- `--force-recreate-venv`: recreate venv
|
|
92
|
+
This command can:
|
|
93
|
+
- install `typescript` and `@types/node`
|
|
94
|
+
- generate `tsconfig.json` (if missing)
|
|
95
|
+
- generate `src/synap.ts` typed wrapper (if missing)
|
|
172
96
|
|
|
173
|
-
|
|
174
|
-
- `--project-dir <path>`: target Node project (default: current working directory)
|
|
175
|
-
- `--package-manager <name>`: one of `npm`, `pnpm`, `yarn`, `bun` (auto-detected by lockfile if omitted)
|
|
176
|
-
- `--skip-install`: skip TypeScript dependency install (`typescript`, `@types/node`)
|
|
177
|
-
- `--tsconfig-path <path>`: output path for generated tsconfig (default: `tsconfig.json`)
|
|
178
|
-
- `--wrapper-path <path>`: output path for generated typed wrapper (default: `src/synap.ts`)
|
|
179
|
-
- `--no-wrapper`: do not generate typed wrapper file
|
|
180
|
-
- `--force`: overwrite generated files if they already exist
|
|
181
|
-
|
|
182
|
-
## TypeScript Extension Flow
|
|
183
|
-
|
|
184
|
-
Use this when a project already has `@maximem/synap-js-sdk` installed and wants type safety without rewriting runtime JS:
|
|
185
|
-
|
|
186
|
-
1. Run `npx synap-js-sdk setup-ts`
|
|
187
|
-
2. This installs `typescript` and `@types/node` (unless `--skip-install`)
|
|
188
|
-
3. This generates `tsconfig.json` (if missing)
|
|
189
|
-
4. This generates `src/synap.ts` typed wrapper (unless `--no-wrapper`)
|
|
190
|
-
|
|
191
|
-
Programmatic alternative:
|
|
192
|
-
|
|
193
|
-
```js
|
|
194
|
-
const { setupTypeScriptExtension } = require('@maximem/synap-js-sdk');
|
|
195
|
-
|
|
196
|
-
setupTypeScriptExtension({ projectDir: process.cwd() });
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
## Environment template
|
|
200
|
-
|
|
201
|
-
Use the provided template:
|
|
97
|
+
## Single-Flow Setup (JS + TS)
|
|
202
98
|
|
|
203
99
|
```bash
|
|
204
|
-
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
Template file: `.env.example`
|
|
208
|
-
|
|
209
|
-
## EC2 + Docker flow (recommended)
|
|
210
|
-
|
|
211
|
-
Build time should install Node deps and Python runtime once, not on every container start.
|
|
212
|
-
|
|
213
|
-
```dockerfile
|
|
214
|
-
FROM node:20-bullseye
|
|
215
|
-
|
|
216
|
-
RUN apt-get update && apt-get install -y python3 python3-venv && rm -rf /var/lib/apt/lists/*
|
|
217
|
-
|
|
218
|
-
WORKDIR /app
|
|
219
|
-
COPY package*.json ./
|
|
220
|
-
RUN npm ci
|
|
221
|
-
|
|
222
|
-
# Install wrapper python runtime deterministically
|
|
223
|
-
RUN npx synap-js-sdk setup --python python3 --sdk-home /opt/synap-js-sdk --sdk-version <PY_SDK_VERSION>
|
|
224
|
-
|
|
225
|
-
COPY . .
|
|
226
|
-
|
|
227
|
-
ENV SYNAP_JS_SDK_HOME=/opt/synap-js-sdk
|
|
228
|
-
ENV SYNAP_BASE_URL=http://<synap-api-host>:8000
|
|
229
|
-
ENV SYNAP_GRPC_HOST=<synap-grpc-host>
|
|
230
|
-
ENV SYNAP_GRPC_PORT=50051
|
|
231
|
-
ENV SYNAP_GRPC_TLS=false
|
|
232
|
-
|
|
233
|
-
CMD ["node", "server.js"]
|
|
100
|
+
npm install @maximem/synap-js-sdk && npx synap-js-sdk setup --sdk-version 0.1.1 && npx synap-js-sdk setup-ts
|
|
234
101
|
```
|
|
235
102
|
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
1. Node app starts.
|
|
239
|
-
2. First Synap call starts Python bridge process.
|
|
240
|
-
3. Bridge sends `init` to Python SDK.
|
|
241
|
-
4. API methods run through JSON-RPC.
|
|
242
|
-
5. On shutdown, wrapper sends `shutdown` and stops bridge.
|
|
243
|
-
|
|
244
|
-
## Versioning and compatibility matrix
|
|
245
|
-
|
|
246
|
-
Recommended policy:
|
|
247
|
-
|
|
248
|
-
1. Keep JS and Python SDK on the same semantic version (`x.y.z`).
|
|
249
|
-
2. Publish JS only after Python package `x.y.z` is available.
|
|
250
|
-
3. CI release pipeline should verify `pip install maximem-synap==x.y.z` before npm publish.
|
|
251
|
-
|
|
252
|
-
Even with same-version policy, keep a compatibility table in docs for rollback safety:
|
|
103
|
+
## CLI Commands
|
|
253
104
|
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
|
|
105
|
+
```bash
|
|
106
|
+
synap-js-sdk setup [options]
|
|
107
|
+
synap-js-sdk setup-ts [options]
|
|
257
108
|
```
|
|
258
|
-
|
|
259
|
-
## Failure modes to expect
|
|
260
|
-
|
|
261
|
-
- Python not installed or not found
|
|
262
|
-
- Bridge process crash/restart
|
|
263
|
-
- pip install failure due to network/private index
|
|
264
|
-
- auth/instance id missing or expired
|
|
265
|
-
|
|
266
|
-
Treat this SDK as a managed dual-runtime component in production.
|
package/bridge/synap_bridge.py
CHANGED
|
@@ -168,11 +168,12 @@ async def handle_add_memory(params: dict) -> dict:
|
|
|
168
168
|
start = time.perf_counter()
|
|
169
169
|
|
|
170
170
|
step = time.perf_counter()
|
|
171
|
+
mode = params.get("mode", "long-range")
|
|
171
172
|
create_result = await sdk.memories.create(
|
|
172
173
|
document=transcript,
|
|
173
174
|
document_type="ai-chat-conversation",
|
|
174
175
|
user_id=user_id,
|
|
175
|
-
mode=
|
|
176
|
+
mode=mode,
|
|
176
177
|
)
|
|
177
178
|
append_step(timings, "memories_create", step)
|
|
178
179
|
|
|
@@ -243,6 +244,7 @@ async def handle_search_memory(params: dict) -> dict:
|
|
|
243
244
|
user_id = params["user_id"]
|
|
244
245
|
query = params["query"]
|
|
245
246
|
max_results = params.get("max_results", 10)
|
|
247
|
+
mode = params.get("mode", "fast")
|
|
246
248
|
|
|
247
249
|
start = time.perf_counter()
|
|
248
250
|
|
|
@@ -252,7 +254,7 @@ async def handle_search_memory(params: dict) -> dict:
|
|
|
252
254
|
search_query=[query],
|
|
253
255
|
max_results=max_results,
|
|
254
256
|
types=["all"],
|
|
255
|
-
mode=
|
|
257
|
+
mode=mode,
|
|
256
258
|
)
|
|
257
259
|
append_step(timings, "context_fetch", step)
|
|
258
260
|
|
|
@@ -293,6 +295,7 @@ async def handle_get_memories(params: dict) -> dict:
|
|
|
293
295
|
timings: List[dict] = []
|
|
294
296
|
|
|
295
297
|
user_id = params["user_id"]
|
|
298
|
+
mode = params.get("mode", "fast")
|
|
296
299
|
|
|
297
300
|
start = time.perf_counter()
|
|
298
301
|
|
|
@@ -302,7 +305,7 @@ async def handle_get_memories(params: dict) -> dict:
|
|
|
302
305
|
search_query=[],
|
|
303
306
|
max_results=100,
|
|
304
307
|
types=["all"],
|
|
305
|
-
mode=
|
|
308
|
+
mode=mode,
|
|
306
309
|
)
|
|
307
310
|
append_step(timings, "context_fetch_all", step)
|
|
308
311
|
|
package/package.json
CHANGED
package/src/synap-client.js
CHANGED
|
@@ -14,32 +14,33 @@ class SynapClient {
|
|
|
14
14
|
await this.bridge.ensureStarted();
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async addMemory({ userId, messages }) {
|
|
17
|
+
async addMemory({ userId, messages, mode }) {
|
|
18
18
|
this.#assert(userId, 'userId is required');
|
|
19
19
|
this.#assert(Array.isArray(messages), 'messages must be an array');
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
);
|
|
21
|
+
const params = { user_id: userId, messages };
|
|
22
|
+
if (mode !== undefined) params.mode = mode;
|
|
23
|
+
|
|
24
|
+
return this.bridge.call('add_memory', params, this.options.ingestTimeoutMs);
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
async searchMemory({ userId, query, maxResults = 10 }) {
|
|
27
|
+
async searchMemory({ userId, query, maxResults = 10, mode }) {
|
|
29
28
|
this.#assert(userId, 'userId is required');
|
|
30
29
|
this.#assert(query, 'query is required');
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
});
|
|
31
|
+
const params = { user_id: userId, query, max_results: maxResults };
|
|
32
|
+
if (mode !== undefined) params.mode = mode;
|
|
33
|
+
|
|
34
|
+
return this.bridge.call('search_memory', params);
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
async getMemories({ userId }) {
|
|
37
|
+
async getMemories({ userId, mode }) {
|
|
40
38
|
this.#assert(userId, 'userId is required');
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
const params = { user_id: userId };
|
|
41
|
+
if (mode !== undefined) params.mode = mode;
|
|
42
|
+
|
|
43
|
+
return this.bridge.call('get_memories', params);
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
async deleteMemory({ userId, memoryId = null }) {
|