@maximem/synap-js-sdk 0.3.0 → 1.0.0-beta.0
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/MIGRATING.md +146 -0
- package/README.md +96 -83
- package/bin/synap-js-sdk.js +45 -122
- package/dist/anticipation-cache-BgkqcTPJ.d.cts +180 -0
- package/dist/anticipation-cache-BgkqcTPJ.d.ts +180 -0
- package/dist/anticipation-cache-D5YHEPV3.js +10 -0
- package/dist/anticipation-cache-D5YHEPV3.js.map +1 -0
- package/dist/anticipation-cache-JBZHTJ3O.cjs +10 -0
- package/dist/anticipation-cache-JBZHTJ3O.cjs.map +1 -0
- package/dist/chunk-5SC3ELNK.js +856 -0
- package/dist/chunk-5SC3ELNK.js.map +1 -0
- package/dist/chunk-HR5Y3KXS.cjs +172 -0
- package/dist/chunk-HR5Y3KXS.cjs.map +1 -0
- package/dist/chunk-NIDPTBNC.cjs +800 -0
- package/dist/chunk-NIDPTBNC.cjs.map +1 -0
- package/dist/chunk-QBCVMPGK.js +28 -0
- package/dist/chunk-QBCVMPGK.js.map +1 -0
- package/dist/chunk-T3NZBIV2.js +172 -0
- package/dist/chunk-T3NZBIV2.js.map +1 -0
- package/dist/chunk-TCEP5OVR.js +800 -0
- package/dist/chunk-TCEP5OVR.js.map +1 -0
- package/dist/chunk-VXRCBMCY.cjs +856 -0
- package/dist/chunk-VXRCBMCY.cjs.map +1 -0
- package/dist/chunk-ZKOJDUN4.cjs +28 -0
- package/dist/chunk-ZKOJDUN4.cjs.map +1 -0
- package/dist/env-55ULHNJZ.cjs +11 -0
- package/dist/env-55ULHNJZ.cjs.map +1 -0
- package/dist/env-QCUKKW36.js +11 -0
- package/dist/env-QCUKKW36.js.map +1 -0
- package/dist/grpc/index.cjs +87 -0
- package/dist/grpc/index.cjs.map +1 -0
- package/dist/grpc/index.d.cts +162 -0
- package/dist/grpc/index.d.ts +162 -0
- package/dist/grpc/index.js +87 -0
- package/dist/grpc/index.js.map +1 -0
- package/dist/index.cjs +2111 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1477 -0
- package/dist/index.d.ts +1477 -0
- package/dist/index.js +2111 -0
- package/dist/index.js.map +1 -0
- package/dist/stream-client-ME5N5NK4.js +7 -0
- package/dist/stream-client-ME5N5NK4.js.map +1 -0
- package/dist/stream-client-ZN6ADZBR.cjs +7 -0
- package/dist/stream-client-ZN6ADZBR.cjs.map +1 -0
- package/package.json +68 -23
- package/.env.example +0 -39
- package/bridge/synap_bridge.py +0 -768
- package/src/bridge-manager.js +0 -262
- package/src/errors.js +0 -168
- package/src/index.js +0 -13
- package/src/runtime.js +0 -161
- package/src/setup-typescript.js +0 -161
- package/src/synap-client.js +0 -464
- package/types/index.d.ts +0 -475
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1477 @@
|
|
|
1
|
+
import { a as AnticipationCacheSnapshot } from './anticipation-cache-BgkqcTPJ.cjs';
|
|
2
|
+
export { b as ANY_SCOPE, A as AnticipationCache, c as AnticipationCacheOptions, B as BundleItem, C as ContextBundle, E as ExitReason, L as LookupParams, d as LookupResult, e as LookupTelemetry, S as SnapshotBundle, f as SnapshotItemPreview, g as SnapshotItemRecord } from './anticipation-cache-BgkqcTPJ.cjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* AUTOGENERATED FROM synap/sdk/CONTRACT/endpoints.yaml -- DO NOT EDIT.
|
|
6
|
+
* Regenerate with synap/sdk/scripts/sync-contract.sh.
|
|
7
|
+
*
|
|
8
|
+
* The /api/v1 vs /v1 prefix split is intentional and load-bearing. See the
|
|
9
|
+
* contract file: normalising it 404s every affected call in production.
|
|
10
|
+
*/
|
|
11
|
+
interface EndpointSpec {
|
|
12
|
+
readonly method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
13
|
+
readonly path: string;
|
|
14
|
+
/**
|
|
15
|
+
* Whether a retry after an ambiguous failure is safe.
|
|
16
|
+
*
|
|
17
|
+
* False here means a retry can double-ingest and therefore double-bill.
|
|
18
|
+
* See defect D / gotcha G-L in the migration plan.
|
|
19
|
+
*/
|
|
20
|
+
readonly idempotent: boolean;
|
|
21
|
+
}
|
|
22
|
+
declare const ENDPOINTS: {
|
|
23
|
+
readonly whoami: {
|
|
24
|
+
readonly method: "GET";
|
|
25
|
+
readonly path: "/api/v1/auth/whoami";
|
|
26
|
+
readonly idempotent: true;
|
|
27
|
+
};
|
|
28
|
+
readonly memories_create: {
|
|
29
|
+
readonly method: "POST";
|
|
30
|
+
readonly path: "/api/v1/memories/create";
|
|
31
|
+
readonly idempotent: false;
|
|
32
|
+
};
|
|
33
|
+
readonly memories_batch: {
|
|
34
|
+
readonly method: "POST";
|
|
35
|
+
readonly path: "/api/v1/memories/batch";
|
|
36
|
+
readonly idempotent: false;
|
|
37
|
+
};
|
|
38
|
+
readonly memories_upload: {
|
|
39
|
+
readonly method: "POST";
|
|
40
|
+
readonly path: "/api/v1/memories/upload";
|
|
41
|
+
readonly idempotent: false;
|
|
42
|
+
};
|
|
43
|
+
readonly memories_status: {
|
|
44
|
+
readonly method: "GET";
|
|
45
|
+
readonly path: "/api/v1/memories/status/{ingestion_id}";
|
|
46
|
+
readonly idempotent: true;
|
|
47
|
+
};
|
|
48
|
+
readonly memories_get: {
|
|
49
|
+
readonly method: "GET";
|
|
50
|
+
readonly path: "/api/v1/memories/{memory_id}";
|
|
51
|
+
readonly idempotent: true;
|
|
52
|
+
};
|
|
53
|
+
readonly memories_update: {
|
|
54
|
+
readonly method: "PATCH";
|
|
55
|
+
readonly path: "/api/v1/memories/{memory_id}";
|
|
56
|
+
readonly idempotent: false;
|
|
57
|
+
};
|
|
58
|
+
readonly memories_delete: {
|
|
59
|
+
readonly method: "DELETE";
|
|
60
|
+
readonly path: "/api/v1/memories/{memory_id}";
|
|
61
|
+
readonly idempotent: true;
|
|
62
|
+
};
|
|
63
|
+
readonly context_fetch_user: {
|
|
64
|
+
readonly method: "POST";
|
|
65
|
+
readonly path: "/v1/context/user/fetch";
|
|
66
|
+
readonly idempotent: true;
|
|
67
|
+
};
|
|
68
|
+
readonly context_fetch_customer: {
|
|
69
|
+
readonly method: "POST";
|
|
70
|
+
readonly path: "/v1/context/customer/fetch";
|
|
71
|
+
readonly idempotent: true;
|
|
72
|
+
};
|
|
73
|
+
readonly context_fetch_client: {
|
|
74
|
+
readonly method: "POST";
|
|
75
|
+
readonly path: "/v1/context/client/fetch";
|
|
76
|
+
readonly idempotent: true;
|
|
77
|
+
};
|
|
78
|
+
readonly context_fetch_conversation: {
|
|
79
|
+
readonly method: "POST";
|
|
80
|
+
readonly path: "/v1/context/conversation/fetch";
|
|
81
|
+
readonly idempotent: true;
|
|
82
|
+
};
|
|
83
|
+
readonly context_for_prompt: {
|
|
84
|
+
readonly method: "GET";
|
|
85
|
+
readonly path: "/v1/conversations/{conversation_id}/context-for-prompt";
|
|
86
|
+
readonly idempotent: true;
|
|
87
|
+
};
|
|
88
|
+
readonly conversations_ingest: {
|
|
89
|
+
readonly method: "POST";
|
|
90
|
+
readonly path: "/v1/conversations/ingest";
|
|
91
|
+
readonly idempotent: false;
|
|
92
|
+
};
|
|
93
|
+
readonly conversations_messages: {
|
|
94
|
+
readonly method: "POST";
|
|
95
|
+
readonly path: "/v1/conversations/messages";
|
|
96
|
+
readonly idempotent: false;
|
|
97
|
+
};
|
|
98
|
+
readonly conversations_messages_batch: {
|
|
99
|
+
readonly method: "POST";
|
|
100
|
+
readonly path: "/v1/conversations/messages/batch";
|
|
101
|
+
readonly idempotent: false;
|
|
102
|
+
};
|
|
103
|
+
readonly conversations_compact: {
|
|
104
|
+
readonly method: "POST";
|
|
105
|
+
readonly path: "/v1/conversations/compact";
|
|
106
|
+
readonly idempotent: false;
|
|
107
|
+
};
|
|
108
|
+
readonly conversations_compacted: {
|
|
109
|
+
readonly method: "GET";
|
|
110
|
+
readonly path: "/v1/conversations/{conversation_id}/compacted";
|
|
111
|
+
readonly idempotent: true;
|
|
112
|
+
};
|
|
113
|
+
readonly conversations_compaction_status: {
|
|
114
|
+
readonly method: "GET";
|
|
115
|
+
readonly path: "/v1/conversations/{conversation_id}/compaction/status";
|
|
116
|
+
readonly idempotent: true;
|
|
117
|
+
};
|
|
118
|
+
readonly user_profile: {
|
|
119
|
+
readonly method: "GET";
|
|
120
|
+
readonly path: "/v1/users/{user_id}/profile";
|
|
121
|
+
readonly idempotent: true;
|
|
122
|
+
};
|
|
123
|
+
readonly credits_balance: {
|
|
124
|
+
readonly method: "GET";
|
|
125
|
+
readonly path: "/v1/credits/balance";
|
|
126
|
+
readonly idempotent: true;
|
|
127
|
+
};
|
|
128
|
+
readonly credits_ledger: {
|
|
129
|
+
readonly method: "GET";
|
|
130
|
+
readonly path: "/v1/credits/ledger";
|
|
131
|
+
readonly idempotent: true;
|
|
132
|
+
};
|
|
133
|
+
readonly credits_estimate: {
|
|
134
|
+
readonly method: "POST";
|
|
135
|
+
readonly path: "/v1/credits/estimate";
|
|
136
|
+
readonly idempotent: true;
|
|
137
|
+
};
|
|
138
|
+
readonly credits_redeem: {
|
|
139
|
+
readonly method: "POST";
|
|
140
|
+
readonly path: "/v1/credits/redeem";
|
|
141
|
+
readonly idempotent: false;
|
|
142
|
+
};
|
|
143
|
+
readonly telemetry_batch: {
|
|
144
|
+
readonly method: "POST";
|
|
145
|
+
readonly path: "/v1/telemetry/batch";
|
|
146
|
+
readonly idempotent: false;
|
|
147
|
+
};
|
|
148
|
+
};
|
|
149
|
+
type EndpointName = keyof typeof ENDPOINTS;
|
|
150
|
+
/** Substitute `{placeholder}` segments. Values are URL-encoded.
|
|
151
|
+
*
|
|
152
|
+
* Encoding matters: an unencoded id containing `/` or `?` silently
|
|
153
|
+
* retargets the request at a different route.
|
|
154
|
+
*/
|
|
155
|
+
declare function resolvePath(name: EndpointName, params?: Readonly<Record<string, string | number>>): string;
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Retry policy, mirroring `maximem_synap/resilience/retry.py` plus the
|
|
159
|
+
* idempotency gate added there for defect D.
|
|
160
|
+
*
|
|
161
|
+
* ## Why idempotency is part of the retry decision
|
|
162
|
+
*
|
|
163
|
+
* The obvious retry rule is "retry transient errors". That rule double-bills.
|
|
164
|
+
*
|
|
165
|
+
* `POST /api/v1/memories/create` is metered ingestion. If the request reached
|
|
166
|
+
* the server, was processed, and the *response* was lost, a retry ingests the
|
|
167
|
+
* same content twice and bills for it twice. The client cannot tell that case
|
|
168
|
+
* apart from "the request never arrived" by looking at the error type alone.
|
|
169
|
+
*
|
|
170
|
+
* So retries are gated on two independent questions:
|
|
171
|
+
*
|
|
172
|
+
* 1. Is the error transient? (worth retrying at all)
|
|
173
|
+
* 2. Is the outcome *knowable*? (safe to retry a non-idempotent call)
|
|
174
|
+
*
|
|
175
|
+
* A connection error means the request provably never reached the application,
|
|
176
|
+
* so the outcome is known: nothing happened. A read timeout means the request
|
|
177
|
+
* may well have been processed. That is the ambiguous case, and for a
|
|
178
|
+
* non-idempotent method it is where we stop.
|
|
179
|
+
*
|
|
180
|
+
* The residual window -- server accepted the request, began processing, then
|
|
181
|
+
* died before responding -- cannot be closed from the client at all. Closing it
|
|
182
|
+
* requires a server-honoured idempotency key on the ingest route. Until that
|
|
183
|
+
* exists, this policy narrows the window rather than eliminating it.
|
|
184
|
+
*/
|
|
185
|
+
interface RetryPolicy {
|
|
186
|
+
maxAttempts: number;
|
|
187
|
+
/** Base delay in seconds. */
|
|
188
|
+
backoffBase: number;
|
|
189
|
+
/** Delay cap in seconds. */
|
|
190
|
+
backoffMax: number;
|
|
191
|
+
/** Randomise the delay to avoid a thundering herd. */
|
|
192
|
+
backoffJitter: boolean;
|
|
193
|
+
}
|
|
194
|
+
declare const DEFAULT_RETRY_POLICY: RetryPolicy;
|
|
195
|
+
interface RetryDecisionInput {
|
|
196
|
+
error: unknown;
|
|
197
|
+
/** 1-based. */
|
|
198
|
+
attempt: number;
|
|
199
|
+
policy: RetryPolicy;
|
|
200
|
+
method: string;
|
|
201
|
+
/**
|
|
202
|
+
* True when the request may have been processed by the server despite the
|
|
203
|
+
* error. Read timeouts and mid-flight disconnects are ambiguous; connection
|
|
204
|
+
* errors and definitive HTTP status responses are not.
|
|
205
|
+
*/
|
|
206
|
+
outcomeUnknown: boolean;
|
|
207
|
+
/** Overrides idempotency for a route, e.g. a read-only POST. */
|
|
208
|
+
idempotent?: boolean;
|
|
209
|
+
}
|
|
210
|
+
interface RetryDecision {
|
|
211
|
+
retry: boolean;
|
|
212
|
+
/** Seconds to wait before the next attempt. */
|
|
213
|
+
delaySeconds: number;
|
|
214
|
+
reason: string;
|
|
215
|
+
}
|
|
216
|
+
declare function shouldRetry(input: RetryDecisionInput): RetryDecision;
|
|
217
|
+
|
|
218
|
+
interface KeepAliveOptions {
|
|
219
|
+
keepAliveExpiryMs?: number;
|
|
220
|
+
maxConnections?: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Native HTTP transport.
|
|
225
|
+
*
|
|
226
|
+
* Port of `maximem_synap/transport/http_client.py`. Uses global `fetch` so the
|
|
227
|
+
* same code runs on Node, Edge, Workers and Bun, with an optional undici
|
|
228
|
+
* dispatcher on Node to restore Python's connection reuse (see keepalive.ts).
|
|
229
|
+
*/
|
|
230
|
+
|
|
231
|
+
declare const DEFAULT_BASE_URL = "https://synap-cloud-prod.maximem.ai";
|
|
232
|
+
interface TimeoutConfig {
|
|
233
|
+
/** Seconds. Mirrors TimeoutConfig in the Python SDK. */
|
|
234
|
+
connect: number;
|
|
235
|
+
read: number;
|
|
236
|
+
write: number;
|
|
237
|
+
}
|
|
238
|
+
declare const DEFAULT_TIMEOUTS: TimeoutConfig;
|
|
239
|
+
interface Credentials {
|
|
240
|
+
apiKey: string;
|
|
241
|
+
clientId: string;
|
|
242
|
+
instanceId: string;
|
|
243
|
+
}
|
|
244
|
+
interface HttpTransportOptions {
|
|
245
|
+
credentials: Credentials;
|
|
246
|
+
baseUrl?: string;
|
|
247
|
+
timeouts?: Partial<TimeoutConfig>;
|
|
248
|
+
retryPolicy?: Partial<RetryPolicy>;
|
|
249
|
+
keepAlive?: KeepAliveOptions & {
|
|
250
|
+
heartbeatIntervalMs?: number;
|
|
251
|
+
};
|
|
252
|
+
userAgent?: string;
|
|
253
|
+
/** Injected in tests. Defaults to global fetch. */
|
|
254
|
+
fetchImpl?: typeof fetch;
|
|
255
|
+
}
|
|
256
|
+
interface RequestOptions {
|
|
257
|
+
pathParams?: Record<string, string | number>;
|
|
258
|
+
query?: Record<string, string | number | boolean | undefined>;
|
|
259
|
+
body?: unknown;
|
|
260
|
+
/**
|
|
261
|
+
* Send `body` as-is instead of JSON-encoding it, and drop the JSON
|
|
262
|
+
* Content-Type so the runtime can set `multipart/form-data` with its own
|
|
263
|
+
* boundary. Setting Content-Type by hand for FormData produces a body the
|
|
264
|
+
* server cannot parse, because the boundary will not match.
|
|
265
|
+
*/
|
|
266
|
+
rawBody?: boolean;
|
|
267
|
+
correlationId?: string;
|
|
268
|
+
/** Overrides the endpoint's declared idempotency. */
|
|
269
|
+
idempotent?: boolean;
|
|
270
|
+
signal?: AbortSignal;
|
|
271
|
+
}
|
|
272
|
+
declare class HttpTransport {
|
|
273
|
+
#private;
|
|
274
|
+
readonly baseUrl: string;
|
|
275
|
+
timeouts: TimeoutConfig;
|
|
276
|
+
retryPolicy: RetryPolicy;
|
|
277
|
+
private readonly userAgent;
|
|
278
|
+
private readonly fetchImpl;
|
|
279
|
+
private readonly keepAliveOptions;
|
|
280
|
+
private readonly heartbeat;
|
|
281
|
+
private closed;
|
|
282
|
+
constructor(options: HttpTransportOptions);
|
|
283
|
+
/** Start keeping the connection warm. Opt-in: it is pointless in serverless. */
|
|
284
|
+
startHeartbeat(): void;
|
|
285
|
+
/**
|
|
286
|
+
* Release timers. Safe to call more than once.
|
|
287
|
+
*
|
|
288
|
+
* This is the supported shutdown path, deliberately explicit rather than
|
|
289
|
+
* hooked to `process.on('exit')`: those handlers leak a listener per client,
|
|
290
|
+
* never fire in Lambda, and `process` does not exist in Workers (gotcha G-I).
|
|
291
|
+
*/
|
|
292
|
+
/**
|
|
293
|
+
* A COPY of the current credentials.
|
|
294
|
+
*
|
|
295
|
+
* A copy, not the live object: handing out the internal reference is how
|
|
296
|
+
* `client.transport.credentials.apiKey` became readable and mutable from
|
|
297
|
+
* outside in the first place.
|
|
298
|
+
*/
|
|
299
|
+
currentCredentials(): Credentials;
|
|
300
|
+
/** Write back identity resolved from `GET /api/v1/auth/whoami`. */
|
|
301
|
+
updateCredentials(patch: Partial<Credentials>): void;
|
|
302
|
+
setTimeouts(timeouts: Partial<TimeoutConfig>): void;
|
|
303
|
+
/** `null` restores the default policy, matching Python's `retry_policy=None`. */
|
|
304
|
+
setRetryPolicy(policy: Partial<RetryPolicy> | null): void;
|
|
305
|
+
close(): void;
|
|
306
|
+
request<T = unknown>(name: EndpointName, options?: RequestOptions): Promise<T>;
|
|
307
|
+
private attempt;
|
|
308
|
+
private buildUrl;
|
|
309
|
+
private buildHeaders;
|
|
310
|
+
/** Unauthenticated and unmetered, exactly like the Python heartbeat. */
|
|
311
|
+
private pingHealth;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Whether the server may have processed the request despite this error.
|
|
315
|
+
*
|
|
316
|
+
* This is the input to the double-billing gate in retry.ts, so the bias is
|
|
317
|
+
* deliberate: anything we cannot positively rule out counts as ambiguous.
|
|
318
|
+
*/
|
|
319
|
+
declare function isOutcomeUnknown(error: unknown): boolean;
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Context shapes.
|
|
323
|
+
*
|
|
324
|
+
* There are deliberately TWO of these, and they are both live in production:
|
|
325
|
+
*
|
|
326
|
+
* - **Raw snake_case** (`RawContext`), returned by the namespaced surface
|
|
327
|
+
* (`client.user.context.fetch(...)`), which passes `result.context` through
|
|
328
|
+
* untouched.
|
|
329
|
+
* - **Normalised camelCase** (`NormalisedContext`), returned by the legacy
|
|
330
|
+
* top-level methods (`client.fetchUserContext(...)`).
|
|
331
|
+
*
|
|
332
|
+
* Converging them would be a clean improvement and would also break one of the
|
|
333
|
+
* two sets of existing consumers, so it is a 2.0 change, not a port change.
|
|
334
|
+
* See gotcha G-B in the migration plan. Do not "tidy" this.
|
|
335
|
+
*/
|
|
336
|
+
type Json = Record<string, unknown>;
|
|
337
|
+
interface RawContextItem {
|
|
338
|
+
id?: string;
|
|
339
|
+
item_id?: string;
|
|
340
|
+
content?: string;
|
|
341
|
+
confidence?: number;
|
|
342
|
+
source?: string;
|
|
343
|
+
extracted_at?: string | null;
|
|
344
|
+
metadata?: Json;
|
|
345
|
+
event_date?: string | null;
|
|
346
|
+
valid_until?: string | null;
|
|
347
|
+
temporal_category?: string | null;
|
|
348
|
+
temporal_confidence?: number;
|
|
349
|
+
[key: string]: unknown;
|
|
350
|
+
}
|
|
351
|
+
interface RawConversationContext {
|
|
352
|
+
summary?: string | null;
|
|
353
|
+
current_state?: Json;
|
|
354
|
+
current_state_json?: string;
|
|
355
|
+
key_extractions?: Json;
|
|
356
|
+
key_extractions_json?: string;
|
|
357
|
+
recent_turns?: unknown[];
|
|
358
|
+
compaction_id?: string | null;
|
|
359
|
+
compacted_at?: string | null;
|
|
360
|
+
conversation_id?: string | null;
|
|
361
|
+
[key: string]: unknown;
|
|
362
|
+
}
|
|
363
|
+
interface RawContext {
|
|
364
|
+
facts?: RawContextItem[];
|
|
365
|
+
preferences?: RawContextItem[];
|
|
366
|
+
episodes?: RawContextItem[];
|
|
367
|
+
emotions?: RawContextItem[];
|
|
368
|
+
temporal_events?: RawContextItem[];
|
|
369
|
+
conversation_context?: RawConversationContext | null;
|
|
370
|
+
metadata?: Json;
|
|
371
|
+
[key: string]: unknown;
|
|
372
|
+
}
|
|
373
|
+
interface TemporalFields {
|
|
374
|
+
eventDate: string | null;
|
|
375
|
+
validUntil: string | null;
|
|
376
|
+
temporalCategory: string | null;
|
|
377
|
+
temporalConfidence: number;
|
|
378
|
+
}
|
|
379
|
+
interface Fact extends TemporalFields {
|
|
380
|
+
id: string;
|
|
381
|
+
content: string;
|
|
382
|
+
confidence: number;
|
|
383
|
+
source: string;
|
|
384
|
+
extractedAt: string | null;
|
|
385
|
+
metadata: Json;
|
|
386
|
+
}
|
|
387
|
+
interface Preference extends TemporalFields {
|
|
388
|
+
id: string;
|
|
389
|
+
category: string;
|
|
390
|
+
content: string;
|
|
391
|
+
strength: number;
|
|
392
|
+
source: string;
|
|
393
|
+
extractedAt: string | null;
|
|
394
|
+
metadata: Json;
|
|
395
|
+
}
|
|
396
|
+
interface Episode extends TemporalFields {
|
|
397
|
+
id: string;
|
|
398
|
+
summary: string;
|
|
399
|
+
occurredAt: string | null;
|
|
400
|
+
significance: number;
|
|
401
|
+
participants: unknown[];
|
|
402
|
+
metadata: Json;
|
|
403
|
+
}
|
|
404
|
+
interface Emotion extends TemporalFields {
|
|
405
|
+
id: string;
|
|
406
|
+
emotionType: string;
|
|
407
|
+
intensity: number;
|
|
408
|
+
detectedAt: string | null;
|
|
409
|
+
context: string;
|
|
410
|
+
metadata: Json;
|
|
411
|
+
}
|
|
412
|
+
interface TemporalEvent {
|
|
413
|
+
id: string;
|
|
414
|
+
content: string;
|
|
415
|
+
eventDate: string | null;
|
|
416
|
+
validUntil: string | null;
|
|
417
|
+
/**
|
|
418
|
+
* Nullable despite the `''` default in the normaliser: `pickDefined` skips
|
|
419
|
+
* only `undefined`, so an explicit server `null` is preserved and the
|
|
420
|
+
* default never applies. The declared type follows the runtime, not the
|
|
421
|
+
* default.
|
|
422
|
+
*/
|
|
423
|
+
temporalCategory: string | null;
|
|
424
|
+
temporalConfidence: number;
|
|
425
|
+
confidence: number;
|
|
426
|
+
source: string;
|
|
427
|
+
extractedAt: string | null;
|
|
428
|
+
metadata: Json;
|
|
429
|
+
}
|
|
430
|
+
interface ConversationContext {
|
|
431
|
+
summary: string | null;
|
|
432
|
+
currentState: Json;
|
|
433
|
+
keyExtractions: Json;
|
|
434
|
+
recentTurns: unknown[];
|
|
435
|
+
compactionId: string | null;
|
|
436
|
+
compactedAt: string | null;
|
|
437
|
+
conversationId: string | null;
|
|
438
|
+
}
|
|
439
|
+
interface ContextMetadata {
|
|
440
|
+
correlationId: string;
|
|
441
|
+
ttlSeconds: number;
|
|
442
|
+
source: string;
|
|
443
|
+
retrievedAt: string | null;
|
|
444
|
+
compactionApplied: boolean | null;
|
|
445
|
+
}
|
|
446
|
+
interface NormalisedContext {
|
|
447
|
+
facts: Fact[];
|
|
448
|
+
preferences: Preference[];
|
|
449
|
+
episodes: Episode[];
|
|
450
|
+
emotions: Emotion[];
|
|
451
|
+
temporalEvents: TemporalEvent[];
|
|
452
|
+
conversationContext: ConversationContext | null;
|
|
453
|
+
metadata: ContextMetadata;
|
|
454
|
+
rawResponse: Json;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Fetch options.
|
|
458
|
+
*
|
|
459
|
+
* Both spellings of every id are accepted. The removed wrapper did this
|
|
460
|
+
* (`pickDefined(args.user_id, args.userId)`) and callers depend on it, so
|
|
461
|
+
* rejecting one spelling would be a silent breaking change.
|
|
462
|
+
*/
|
|
463
|
+
interface FetchOptions {
|
|
464
|
+
user_id?: string;
|
|
465
|
+
userId?: string;
|
|
466
|
+
customer_id?: string;
|
|
467
|
+
customerId?: string;
|
|
468
|
+
conversation_id?: string;
|
|
469
|
+
conversationId?: string;
|
|
470
|
+
search_query?: string[];
|
|
471
|
+
searchQuery?: string[];
|
|
472
|
+
max_results?: number;
|
|
473
|
+
maxResults?: number;
|
|
474
|
+
types?: string[];
|
|
475
|
+
mode?: string;
|
|
476
|
+
precision_level?: string;
|
|
477
|
+
precisionLevel?: string;
|
|
478
|
+
/** Sent only when explicitly false, matching the Python controllers. */
|
|
479
|
+
include_conversation_context?: boolean;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* Flatten typed context collections into one memory list.
|
|
484
|
+
*
|
|
485
|
+
* A faithful port of `flatten_context_items` from the 0.3.x bridge, which is
|
|
486
|
+
* what `searchMemory` and `getMemories` returned. The per-type asymmetries are
|
|
487
|
+
* deliberate and are reproduced exactly:
|
|
488
|
+
*
|
|
489
|
+
* - `memory` comes from a different field per type: fact/preference/temporal
|
|
490
|
+
* event use `content`, episode uses `summary`, emotion uses `context`.
|
|
491
|
+
* - `score` likewise: fact -> confidence, preference -> strength,
|
|
492
|
+
* episode -> significance, emotion -> intensity, temporal event ->
|
|
493
|
+
* temporal_confidence.
|
|
494
|
+
* - **episode and emotion carry no `source` key at all.** The bridge simply
|
|
495
|
+
* did not set one. Adding it would be an improvement and a shape change, so
|
|
496
|
+
* it stays absent.
|
|
497
|
+
* - Order is facts, preferences, episodes, emotions, temporal events.
|
|
498
|
+
*/
|
|
499
|
+
|
|
500
|
+
interface FlatMemory {
|
|
501
|
+
id: string;
|
|
502
|
+
memory: string;
|
|
503
|
+
score: number;
|
|
504
|
+
/** Absent for episodes and emotions, matching the 0.3.x bridge. */
|
|
505
|
+
source?: string;
|
|
506
|
+
metadata: Json;
|
|
507
|
+
context_type: 'fact' | 'preference' | 'episode' | 'emotion' | 'temporal_event';
|
|
508
|
+
event_date: string | null;
|
|
509
|
+
valid_until: string | null;
|
|
510
|
+
temporal_category: string | null;
|
|
511
|
+
temporal_confidence: number;
|
|
512
|
+
}
|
|
513
|
+
declare function flattenContextItems(context: RawContext): FlatMemory[];
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Memories namespace. Mirrors `maximem_synap.memories.interface.MemoriesInterface`.
|
|
517
|
+
*
|
|
518
|
+
* ## The request body is built the way Python builds it, on purpose
|
|
519
|
+
*
|
|
520
|
+
* Python constructs a pydantic `CreateMemoryRequest` and posts
|
|
521
|
+
* `model_dump(mode="json")`, which emits **every** field, nulls included, with
|
|
522
|
+
* defaults applied. It is tempting to omit unset keys instead and send a
|
|
523
|
+
* tidier body. Do not: the server sees a different request, and the difference
|
|
524
|
+
* that matters most is `document_type`.
|
|
525
|
+
*
|
|
526
|
+
* `document_type` defaults to `"ai-chat-conversation"`. Leaving it off is not
|
|
527
|
+
* neutral, because the extraction path is type-dependent and the
|
|
528
|
+
* `"document"` type extracts dramatically less from the same text. A body that
|
|
529
|
+
* merely looks cleaner is how you get "the JS SDK stores fewer memories than
|
|
530
|
+
* the Python one from identical input", which is slow and miserable to
|
|
531
|
+
* diagnose.
|
|
532
|
+
*/
|
|
533
|
+
|
|
534
|
+
/** Mirrors the Python DocumentType enum. */
|
|
535
|
+
declare const DOCUMENT_TYPES: readonly ["ai-chat-conversation", "document", "email", "pdf", "image", "audio", "meeting-transcript"];
|
|
536
|
+
type DocumentType = (typeof DOCUMENT_TYPES)[number];
|
|
537
|
+
/** Mirrors the Python IngestMode enum. */
|
|
538
|
+
declare const INGEST_MODES: readonly ["fast", "long-range"];
|
|
539
|
+
type IngestMode = (typeof INGEST_MODES)[number];
|
|
540
|
+
declare const DEFAULT_DOCUMENT_TYPE: DocumentType;
|
|
541
|
+
declare const DEFAULT_INGEST_MODE: IngestMode;
|
|
542
|
+
interface CreateMemoryOptions {
|
|
543
|
+
document: string;
|
|
544
|
+
user_id?: string | null;
|
|
545
|
+
userId?: string | null;
|
|
546
|
+
customer_id?: string | null;
|
|
547
|
+
customerId?: string | null;
|
|
548
|
+
document_type?: DocumentType | string;
|
|
549
|
+
documentType?: DocumentType | string;
|
|
550
|
+
document_id?: string | null;
|
|
551
|
+
documentId?: string | null;
|
|
552
|
+
/** ISO-8601 string or Date. Serialised the way Python serialises a datetime. */
|
|
553
|
+
document_created_at?: string | Date | null;
|
|
554
|
+
documentCreatedAt?: string | Date | null;
|
|
555
|
+
mode?: IngestMode | string;
|
|
556
|
+
metadata?: Json;
|
|
557
|
+
}
|
|
558
|
+
interface CreateMemoryResult {
|
|
559
|
+
ingestion_id?: string;
|
|
560
|
+
status?: string;
|
|
561
|
+
memories_created?: number;
|
|
562
|
+
[key: string]: unknown;
|
|
563
|
+
}
|
|
564
|
+
interface BatchCreateOptions {
|
|
565
|
+
documents: CreateMemoryOptions[];
|
|
566
|
+
fail_fast?: boolean;
|
|
567
|
+
failFast?: boolean;
|
|
568
|
+
}
|
|
569
|
+
interface MemoriesInterface {
|
|
570
|
+
create(options: CreateMemoryOptions): Promise<CreateMemoryResult>;
|
|
571
|
+
batch_create(options: BatchCreateOptions): Promise<Json>;
|
|
572
|
+
create_from_file(options: CreateFromFileOptions): Promise<CreateMemoryResult>;
|
|
573
|
+
get(memoryId: string): Promise<Json>;
|
|
574
|
+
update(options: UpdateMemoryOptions): Promise<Json>;
|
|
575
|
+
delete(memoryId: string): Promise<Json>;
|
|
576
|
+
status(ingestionId: string): Promise<Json>;
|
|
577
|
+
wait_for_completion(ingestionId: string, options?: WaitOptions): Promise<Json>;
|
|
578
|
+
}
|
|
579
|
+
/**
|
|
580
|
+
* Options for `create_from_file`.
|
|
581
|
+
*
|
|
582
|
+
* Exactly one of `file_path`, `file`, or `text` must be supplied, matching
|
|
583
|
+
* Python. `file_path` reads from disk and so is Node-only; `file` takes a
|
|
584
|
+
* Blob/File/Uint8Array and works anywhere, which is the portable route for
|
|
585
|
+
* Edge and Workers.
|
|
586
|
+
*/
|
|
587
|
+
interface CreateFromFileOptions {
|
|
588
|
+
user_id?: string;
|
|
589
|
+
userId?: string;
|
|
590
|
+
customer_id?: string;
|
|
591
|
+
customerId?: string;
|
|
592
|
+
/** "b2b" or "b2c". Defaults to "b2c", as in Python. */
|
|
593
|
+
relationship_type?: string;
|
|
594
|
+
relationshipType?: string;
|
|
595
|
+
/** Node-only: read this path from disk. Uses a lazy `node:fs` import. */
|
|
596
|
+
file_path?: string;
|
|
597
|
+
filePath?: string;
|
|
598
|
+
/** Portable alternative to `file_path`. Pass `filename` alongside a raw buffer. */
|
|
599
|
+
file?: Blob | Uint8Array | ArrayBuffer;
|
|
600
|
+
filename?: string;
|
|
601
|
+
/** Ingest raw text instead of a file. */
|
|
602
|
+
text?: string;
|
|
603
|
+
document_type?: string;
|
|
604
|
+
documentType?: string;
|
|
605
|
+
mode?: IngestMode | string;
|
|
606
|
+
metadata?: Json;
|
|
607
|
+
}
|
|
608
|
+
interface UpdateMemoryOptions {
|
|
609
|
+
memory_id?: string;
|
|
610
|
+
memoryId?: string;
|
|
611
|
+
document: string;
|
|
612
|
+
merge_strategy?: string;
|
|
613
|
+
mergeStrategy?: string;
|
|
614
|
+
document_type?: string;
|
|
615
|
+
documentType?: string;
|
|
616
|
+
metadata?: Json;
|
|
617
|
+
}
|
|
618
|
+
interface WaitOptions {
|
|
619
|
+
/** Seconds. Matches Python's default. */
|
|
620
|
+
timeout_seconds?: number;
|
|
621
|
+
timeoutSeconds?: number;
|
|
622
|
+
poll_interval_seconds?: number;
|
|
623
|
+
pollIntervalSeconds?: number;
|
|
624
|
+
signal?: AbortSignal;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Conversation namespace. Mirrors `ConversationInterface` and
|
|
629
|
+
* `ConversationContextInterface` in the Python SDK.
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
interface RecordMessageOptions {
|
|
633
|
+
conversation_id?: string;
|
|
634
|
+
conversationId?: string;
|
|
635
|
+
role: string;
|
|
636
|
+
content: string;
|
|
637
|
+
user_id?: string;
|
|
638
|
+
userId?: string;
|
|
639
|
+
customer_id?: string;
|
|
640
|
+
customerId?: string;
|
|
641
|
+
session_id?: string;
|
|
642
|
+
sessionId?: string;
|
|
643
|
+
metadata?: Json;
|
|
644
|
+
}
|
|
645
|
+
interface TranscriptTurn {
|
|
646
|
+
role: string;
|
|
647
|
+
content: string;
|
|
648
|
+
[key: string]: unknown;
|
|
649
|
+
}
|
|
650
|
+
interface IngestTranscriptOptions {
|
|
651
|
+
conversation_id?: string;
|
|
652
|
+
conversationId?: string;
|
|
653
|
+
user_id?: string;
|
|
654
|
+
userId?: string;
|
|
655
|
+
transcript: string | TranscriptTurn[];
|
|
656
|
+
customer_id?: string;
|
|
657
|
+
customerId?: string;
|
|
658
|
+
conversation_type?: string;
|
|
659
|
+
conversationType?: string;
|
|
660
|
+
analysis?: Json;
|
|
661
|
+
metadata?: Json;
|
|
662
|
+
started_at?: string | Date;
|
|
663
|
+
startedAt?: string | Date;
|
|
664
|
+
ended_at?: string | Date;
|
|
665
|
+
endedAt?: string | Date;
|
|
666
|
+
}
|
|
667
|
+
interface CompactOptions {
|
|
668
|
+
conversation_id?: string;
|
|
669
|
+
conversationId?: string;
|
|
670
|
+
strategy?: string;
|
|
671
|
+
compaction_level?: string;
|
|
672
|
+
compactionLevel?: string;
|
|
673
|
+
target_tokens?: number;
|
|
674
|
+
targetTokens?: number;
|
|
675
|
+
force?: boolean;
|
|
676
|
+
}
|
|
677
|
+
interface ConversationNamespace {
|
|
678
|
+
record_message(options: RecordMessageOptions): Promise<Json>;
|
|
679
|
+
record_messages_batch(messages: RecordMessageOptions[]): Promise<Json>;
|
|
680
|
+
ingest_transcript(options: IngestTranscriptOptions): Promise<Json>;
|
|
681
|
+
context: {
|
|
682
|
+
fetch(options?: FetchOptions): Promise<RawContext>;
|
|
683
|
+
get_context_for_prompt(options?: {
|
|
684
|
+
conversation_id?: string;
|
|
685
|
+
conversationId?: string;
|
|
686
|
+
style?: string;
|
|
687
|
+
}): Promise<Json>;
|
|
688
|
+
compact(options: CompactOptions): Promise<Json>;
|
|
689
|
+
get_compacted(options: {
|
|
690
|
+
conversation_id?: string;
|
|
691
|
+
conversationId?: string;
|
|
692
|
+
version?: number;
|
|
693
|
+
format?: string;
|
|
694
|
+
}): Promise<Json | null>;
|
|
695
|
+
get_compaction_status(options: {
|
|
696
|
+
conversation_id?: string;
|
|
697
|
+
conversationId?: string;
|
|
698
|
+
} | string): Promise<Json>;
|
|
699
|
+
subscribe_to_compaction_updates(conversationId: string, callback: CompactionCallback): () => void;
|
|
700
|
+
unsubscribe_all_compaction_updates(conversationId?: string): number;
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
type CompactionCallback = (bundle: Json) => unknown;
|
|
704
|
+
/**
|
|
705
|
+
* Called after a successful write with the ids that were written for.
|
|
706
|
+
*
|
|
707
|
+
* Backs `SYNAP_SDK_CACHE_INVALIDATE_ON_WRITE`. The cloud invalidates its own
|
|
708
|
+
* Redis caches on ingest, but that stops at the process boundary: without this
|
|
709
|
+
* the in-SDK anticipation cache keeps serving the pre-write view for the rest
|
|
710
|
+
* of its TTL. Python calls its equivalent from these same three write paths.
|
|
711
|
+
*/
|
|
712
|
+
type WriteInvalidator = (ids: {
|
|
713
|
+
userId?: string | undefined;
|
|
714
|
+
customerId?: string | undefined;
|
|
715
|
+
}) => void;
|
|
716
|
+
|
|
717
|
+
/** User namespace. Mirrors `UserInterface` in the Python SDK. */
|
|
718
|
+
|
|
719
|
+
interface UserNamespace {
|
|
720
|
+
get_profile(options: {
|
|
721
|
+
user_id?: string;
|
|
722
|
+
userId?: string;
|
|
723
|
+
customer_id?: string;
|
|
724
|
+
customerId?: string;
|
|
725
|
+
} | string): Promise<Json>;
|
|
726
|
+
context: {
|
|
727
|
+
fetch(options?: FetchOptions): Promise<RawContext>;
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/** Credits namespace. Mirrors `CreditsInterface` in the Python SDK. */
|
|
732
|
+
|
|
733
|
+
interface EstimateOptions {
|
|
734
|
+
metric_type?: string;
|
|
735
|
+
metricType?: string;
|
|
736
|
+
units?: number;
|
|
737
|
+
item_count?: number;
|
|
738
|
+
itemCount?: number;
|
|
739
|
+
endpoint?: string;
|
|
740
|
+
mode?: string;
|
|
741
|
+
}
|
|
742
|
+
interface CreditsNamespace {
|
|
743
|
+
get_balance(): Promise<Json>;
|
|
744
|
+
get_ledger(options?: {
|
|
745
|
+
limit?: number;
|
|
746
|
+
offset?: number;
|
|
747
|
+
}): Promise<Json>;
|
|
748
|
+
estimate(options: EstimateOptions): Promise<Json>;
|
|
749
|
+
redeem(code: string): Promise<Json>;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Cache namespace. Mirrors `CacheInterface` in the Python SDK.
|
|
754
|
+
*
|
|
755
|
+
* This is a deliberately narrow facade over the AnticipationCache rather than
|
|
756
|
+
* the cache object itself. Exposing the instance directly leaked internals
|
|
757
|
+
* (`client.cache.now` was reachable) and gave JS a different surface from
|
|
758
|
+
* Python for no benefit. The cache is still reachable as
|
|
759
|
+
* `client.anticipationCache` for advanced use.
|
|
760
|
+
*/
|
|
761
|
+
|
|
762
|
+
interface CacheStats {
|
|
763
|
+
bundles: number;
|
|
764
|
+
items: number;
|
|
765
|
+
[key: string]: unknown;
|
|
766
|
+
}
|
|
767
|
+
interface CacheNamespace {
|
|
768
|
+
clear(): void;
|
|
769
|
+
clear_user(userId: string): void;
|
|
770
|
+
clear_customer(customerId: string): void;
|
|
771
|
+
stats(): CacheStats;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/**
|
|
775
|
+
* Instance namespace. Mirrors `InstanceInterface` in the Python SDK.
|
|
776
|
+
*
|
|
777
|
+
* Everything here rides the bidirectional gRPC Listen stream. The stream module
|
|
778
|
+
* is loaded through a lazy `import()` so that importing this SDK on Edge or in
|
|
779
|
+
* a Worker stays safe: grpc-js is built on `node:http2`/`node:net`/`node:tls`
|
|
780
|
+
* and a static import fails the BUILD there, not the call.
|
|
781
|
+
*/
|
|
782
|
+
|
|
783
|
+
interface ListenOptions {
|
|
784
|
+
/** Called with the attempt count each time the stream reconnects. */
|
|
785
|
+
on_reconnect?: (attempt: number) => void;
|
|
786
|
+
onReconnect?: (attempt: number) => void;
|
|
787
|
+
/** Called with a reason string when the stream drops. */
|
|
788
|
+
on_disconnect?: (reason: string) => void;
|
|
789
|
+
onDisconnect?: (reason: string) => void;
|
|
790
|
+
/**
|
|
791
|
+
* Called for every bundle that arrives. Bundles are ALSO stored in the
|
|
792
|
+
* anticipation cache automatically, so `fetch()` finds them without a round
|
|
793
|
+
* trip; this callback is for observing, not for wiring up storage.
|
|
794
|
+
*/
|
|
795
|
+
on_context?: (bundle: Record<string, unknown>) => void;
|
|
796
|
+
onContext?: (bundle: Record<string, unknown>) => void;
|
|
797
|
+
/** Overrides `SYNAP_GRPC_HOST`. */
|
|
798
|
+
host?: string;
|
|
799
|
+
/** Overrides `SYNAP_GRPC_PORT`. */
|
|
800
|
+
port?: number;
|
|
801
|
+
/** Overrides `SYNAP_GRPC_USE_TLS`. Plaintext only makes sense against localhost. */
|
|
802
|
+
use_tls?: boolean;
|
|
803
|
+
useTls?: boolean;
|
|
804
|
+
}
|
|
805
|
+
interface SendMessageOptions {
|
|
806
|
+
content: string;
|
|
807
|
+
role?: string;
|
|
808
|
+
conversation_id?: string;
|
|
809
|
+
conversationId?: string;
|
|
810
|
+
user_id?: string;
|
|
811
|
+
userId?: string;
|
|
812
|
+
customer_id?: string;
|
|
813
|
+
customerId?: string;
|
|
814
|
+
session_id?: string;
|
|
815
|
+
sessionId?: string;
|
|
816
|
+
event_type?: string;
|
|
817
|
+
eventType?: string;
|
|
818
|
+
metadata?: Record<string, string>;
|
|
819
|
+
search_queries?: string[];
|
|
820
|
+
searchQueries?: string[];
|
|
821
|
+
context_types?: string[];
|
|
822
|
+
contextTypes?: string[];
|
|
823
|
+
}
|
|
824
|
+
interface RecordThinkingOptions {
|
|
825
|
+
content: string;
|
|
826
|
+
conversation_id?: string;
|
|
827
|
+
conversationId?: string;
|
|
828
|
+
user_id?: string;
|
|
829
|
+
userId?: string;
|
|
830
|
+
customer_id?: string;
|
|
831
|
+
customerId?: string;
|
|
832
|
+
session_id?: string;
|
|
833
|
+
sessionId?: string;
|
|
834
|
+
metadata?: Record<string, string>;
|
|
835
|
+
}
|
|
836
|
+
interface InstanceNamespace {
|
|
837
|
+
listen(options?: ListenOptions): Promise<void>;
|
|
838
|
+
stop_listening(): Promise<void>;
|
|
839
|
+
send_message(options: SendMessageOptions): Promise<void>;
|
|
840
|
+
record_thinking(options: RecordThinkingOptions): Promise<void>;
|
|
841
|
+
/** Property, not a method, matching Python's InstanceInterface.is_listening. */
|
|
842
|
+
readonly is_listening: boolean;
|
|
843
|
+
/** Not in Python: lets the compaction subscriptions share this one stream. */
|
|
844
|
+
readonly _internal: InstanceInternals;
|
|
845
|
+
}
|
|
846
|
+
/** @internal Shared with the conversation namespace so both use one stream. */
|
|
847
|
+
interface InstanceInternals {
|
|
848
|
+
onCompactionUpdate(conversationId: string, bundle: Record<string, unknown>): void;
|
|
849
|
+
setCompactionDispatcher(dispatch: (conversationId: string, bundle: Record<string, unknown>) => void): void;
|
|
850
|
+
isListening(): boolean;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Cross-scope merge + prompt formatting for `client.fetch()`.
|
|
855
|
+
*
|
|
856
|
+
* Ports Python's `UnifiedContextResponse.merge` and `format_for_prompt` from
|
|
857
|
+
* `models/context.py`. The formatted string is the part customers actually
|
|
858
|
+
* paste into a system prompt, so it is reproduced character for character:
|
|
859
|
+
* section order, the `- ` bullet, the `[scope: x]` / `strength: 0.8` bracket
|
|
860
|
+
* suffixes, the `## User Context` wrapper, and the blank-line joins. A
|
|
861
|
+
* cosmetic drift here shows up as a diff in every prompt a customer builds.
|
|
862
|
+
*/
|
|
863
|
+
|
|
864
|
+
/** The five item collections, in Python's iteration order. */
|
|
865
|
+
declare const ITEM_COLLECTIONS: readonly ["facts", "preferences", "episodes", "emotions", "temporal_events"];
|
|
866
|
+
type ItemCollection = (typeof ITEM_COLLECTIONS)[number];
|
|
867
|
+
interface UnifiedContext {
|
|
868
|
+
facts: RawContextItem[];
|
|
869
|
+
preferences: RawContextItem[];
|
|
870
|
+
episodes: RawContextItem[];
|
|
871
|
+
emotions: RawContextItem[];
|
|
872
|
+
temporal_events: RawContextItem[];
|
|
873
|
+
/** item id -> the scope that supplied it. */
|
|
874
|
+
scope_map: Record<string, string>;
|
|
875
|
+
conversation_context: Json | null;
|
|
876
|
+
profile: Json | null;
|
|
877
|
+
conversations: Json[] | null;
|
|
878
|
+
formatted_context: string;
|
|
879
|
+
scopes_queried: string[];
|
|
880
|
+
total_items: number;
|
|
881
|
+
metadata: Json | null;
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Merge per-scope responses, deduplicating by item id.
|
|
885
|
+
*
|
|
886
|
+
* First scope wins on a duplicate, so the caller's scope order is significant.
|
|
887
|
+
* An item with no usable id is kept rather than dropped: Python indexes
|
|
888
|
+
* `scope_map` by `item.id`, and a missing id there would collide every such
|
|
889
|
+
* item onto one key, so keeping-and-not-mapping is the closest faithful
|
|
890
|
+
* behaviour.
|
|
891
|
+
*/
|
|
892
|
+
declare function mergeScopeResults(scopeResults: ReadonlyArray<readonly [string, RawContext]>): UnifiedContext;
|
|
893
|
+
interface FormatOptions {
|
|
894
|
+
includeScope?: boolean;
|
|
895
|
+
includeConversationContext?: boolean;
|
|
896
|
+
}
|
|
897
|
+
/**
|
|
898
|
+
* Render the merged context for prompt injection.
|
|
899
|
+
*
|
|
900
|
+
* Mirrors `UnifiedContextResponse.format_for_prompt`. Note the two different
|
|
901
|
+
* bracket styles: facts and episodes only ever carry `[scope: x]` appended
|
|
902
|
+
* directly, while preferences, emotions and temporal events build a joined
|
|
903
|
+
* extras list. That asymmetry is in Python and is preserved.
|
|
904
|
+
*/
|
|
905
|
+
declare function formatForPrompt(ctx: UnifiedContext, options?: FormatOptions): string;
|
|
906
|
+
|
|
907
|
+
/**
|
|
908
|
+
* `client.as_tool(...)`: an LLM-ready tool definition for fetching context.
|
|
909
|
+
*
|
|
910
|
+
* Ports Python's `MaximemSynapSDK.as_tool` plus its three module helpers.
|
|
911
|
+
*
|
|
912
|
+
* The point of the helper is that the scope identifiers are CLOSED OVER rather
|
|
913
|
+
* than exposed in the JSON schema. The LLM chooses the query and the limits; it
|
|
914
|
+
* cannot choose whose memory to read. Handing the model a `user_id` parameter
|
|
915
|
+
* is how the per-user privacy filter gets dropped by accident, so the schema
|
|
916
|
+
* deliberately has no such field.
|
|
917
|
+
*/
|
|
918
|
+
|
|
919
|
+
type ToolScope = 'conversation' | 'user' | 'customer' | 'client' | 'unified';
|
|
920
|
+
type ToolStyle = 'openai' | 'anthropic';
|
|
921
|
+
interface AsToolOptions {
|
|
922
|
+
scope?: string;
|
|
923
|
+
user_id?: string;
|
|
924
|
+
userId?: string;
|
|
925
|
+
customer_id?: string;
|
|
926
|
+
customerId?: string;
|
|
927
|
+
conversation_id?: string;
|
|
928
|
+
conversationId?: string;
|
|
929
|
+
name?: string;
|
|
930
|
+
description?: string;
|
|
931
|
+
style?: string;
|
|
932
|
+
}
|
|
933
|
+
type ToolHandler = (callArgs?: Json) => Promise<Json>;
|
|
934
|
+
interface OpenAiToolDefinition {
|
|
935
|
+
type: 'function';
|
|
936
|
+
function: {
|
|
937
|
+
name: string;
|
|
938
|
+
description: string;
|
|
939
|
+
parameters: Json;
|
|
940
|
+
};
|
|
941
|
+
handler: ToolHandler;
|
|
942
|
+
}
|
|
943
|
+
interface AnthropicToolDefinition {
|
|
944
|
+
name: string;
|
|
945
|
+
description: string;
|
|
946
|
+
input_schema: Json;
|
|
947
|
+
handler: ToolHandler;
|
|
948
|
+
}
|
|
949
|
+
type ToolDefinition = OpenAiToolDefinition | AnthropicToolDefinition;
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* SynapClient: the public entry point.
|
|
953
|
+
*
|
|
954
|
+
* Exposes two surfaces, both live in production:
|
|
955
|
+
*
|
|
956
|
+
* - **Namespaced, snake_case** (`client.user.context.fetch(...)`) is the
|
|
957
|
+
* canonical surface and mirrors the Python SDK method for method. It
|
|
958
|
+
* returns raw snake_case.
|
|
959
|
+
* - **Top-level camelCase** (`client.fetchUserContext(...)`) is deprecated but
|
|
960
|
+
* fully supported. It returns the normalised camelCase shape, and it exists
|
|
961
|
+
* because the 0.3.x wrapper had it.
|
|
962
|
+
*
|
|
963
|
+
* They return different shapes on purpose. See gotcha G-B.
|
|
964
|
+
*/
|
|
965
|
+
|
|
966
|
+
interface SynapClientOptions {
|
|
967
|
+
apiKey?: string;
|
|
968
|
+
clientId?: string;
|
|
969
|
+
instanceId?: string;
|
|
970
|
+
baseUrl?: string;
|
|
971
|
+
timeouts?: HttpTransportOptions['timeouts'];
|
|
972
|
+
retryPolicy?: HttpTransportOptions['retryPolicy'];
|
|
973
|
+
keepAlive?: HttpTransportOptions['keepAlive'];
|
|
974
|
+
/**
|
|
975
|
+
* Keep the connection warm with a periodic /health ping.
|
|
976
|
+
*
|
|
977
|
+
* Off by default. A clear win for a long-lived process, pure waste in
|
|
978
|
+
* serverless where the container is frozen between requests anyway.
|
|
979
|
+
*/
|
|
980
|
+
heartbeat?: boolean;
|
|
981
|
+
fetchImpl?: typeof fetch;
|
|
982
|
+
}
|
|
983
|
+
interface ScopedContext {
|
|
984
|
+
context: {
|
|
985
|
+
fetch: (options?: FetchOptions) => Promise<RawContext>;
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
/**
|
|
989
|
+
* Options for `configure()`.
|
|
990
|
+
*
|
|
991
|
+
* The Python-only keys are declared so a config object can be shared between
|
|
992
|
+
* the two SDKs without a type error. They are accepted and ignored: there is
|
|
993
|
+
* no SQLite cache backend and no global logger to replace here.
|
|
994
|
+
*/
|
|
995
|
+
interface ConfigureOptions {
|
|
996
|
+
timeouts?: HttpTransportOptions['timeouts'];
|
|
997
|
+
retryPolicy?: HttpTransportOptions['retryPolicy'] | null;
|
|
998
|
+
retry_policy?: HttpTransportOptions['retryPolicy'] | null;
|
|
999
|
+
/** Accepted and ignored. Python-only. */
|
|
1000
|
+
storage_path?: string;
|
|
1001
|
+
/** Accepted and ignored. Python-only. */
|
|
1002
|
+
cache_backend?: string | null;
|
|
1003
|
+
/** Accepted and ignored. Python-only. */
|
|
1004
|
+
session_timeout_minutes?: number;
|
|
1005
|
+
/** Accepted and ignored. Python-only. */
|
|
1006
|
+
log_level?: string;
|
|
1007
|
+
/** Accepted and ignored. Python-only. */
|
|
1008
|
+
logger?: unknown;
|
|
1009
|
+
}
|
|
1010
|
+
/** Options for the cross-scope `fetch()`. Snake_case, matching Python's kwargs. */
|
|
1011
|
+
interface UnifiedFetchOptions {
|
|
1012
|
+
conversation_id?: string;
|
|
1013
|
+
user_id?: string;
|
|
1014
|
+
customer_id?: string;
|
|
1015
|
+
search_query?: string[];
|
|
1016
|
+
max_results?: number;
|
|
1017
|
+
types?: string[];
|
|
1018
|
+
mode?: string;
|
|
1019
|
+
precision_level?: string;
|
|
1020
|
+
include_conversation_context?: boolean;
|
|
1021
|
+
scopes?: string[];
|
|
1022
|
+
include_scope_labels?: boolean;
|
|
1023
|
+
context_mode?: string;
|
|
1024
|
+
include_profile?: boolean;
|
|
1025
|
+
last_n_conversations?: number;
|
|
1026
|
+
}
|
|
1027
|
+
declare class SynapClient {
|
|
1028
|
+
#private;
|
|
1029
|
+
readonly user: UserNamespace;
|
|
1030
|
+
readonly customer: ScopedContext;
|
|
1031
|
+
readonly client: ScopedContext;
|
|
1032
|
+
readonly conversation: ConversationNamespace;
|
|
1033
|
+
readonly memories: MemoriesInterface;
|
|
1034
|
+
readonly credits: CreditsNamespace;
|
|
1035
|
+
readonly cache: CacheNamespace;
|
|
1036
|
+
readonly instance: InstanceNamespace;
|
|
1037
|
+
constructor(options?: SynapClientOptions);
|
|
1038
|
+
/** @deprecated Use `client.user.context.fetch()`. Note it returns raw snake_case. */
|
|
1039
|
+
fetchUserContext(options?: FetchOptions): Promise<NormalisedContext>;
|
|
1040
|
+
/** @deprecated Use `client.customer.context.fetch()`. */
|
|
1041
|
+
fetchCustomerContext(options?: FetchOptions): Promise<NormalisedContext>;
|
|
1042
|
+
/** @deprecated Use `client.client.context.fetch()`. */
|
|
1043
|
+
fetchClientContext(options?: FetchOptions): Promise<NormalisedContext>;
|
|
1044
|
+
/** @deprecated Use `client.conversation.context.get_context_for_prompt()`. */
|
|
1045
|
+
getContextForPrompt(options?: {
|
|
1046
|
+
conversationId?: string;
|
|
1047
|
+
conversation_id?: string;
|
|
1048
|
+
style?: string;
|
|
1049
|
+
}): Promise<Json>;
|
|
1050
|
+
/**
|
|
1051
|
+
* @deprecated Use `client.user.context.fetch()` and read the typed collections.
|
|
1052
|
+
*
|
|
1053
|
+
* Flattens every context type into one list, exactly as the 0.3.x bridge did.
|
|
1054
|
+
*/
|
|
1055
|
+
searchMemory(options: {
|
|
1056
|
+
userId?: string;
|
|
1057
|
+
user_id?: string;
|
|
1058
|
+
customerId?: string;
|
|
1059
|
+
customer_id?: string;
|
|
1060
|
+
query: string;
|
|
1061
|
+
maxResults?: number;
|
|
1062
|
+
max_results?: number;
|
|
1063
|
+
mode?: string;
|
|
1064
|
+
conversationId?: string;
|
|
1065
|
+
conversation_id?: string;
|
|
1066
|
+
types?: string[];
|
|
1067
|
+
}): Promise<{
|
|
1068
|
+
results: FlatMemory[];
|
|
1069
|
+
count: number;
|
|
1070
|
+
}>;
|
|
1071
|
+
/**
|
|
1072
|
+
* @deprecated Use `client.user.context.fetch()` with an empty `search_query`.
|
|
1073
|
+
*
|
|
1074
|
+
* Note the default of 100, not 10: it matches the 0.3.x bridge.
|
|
1075
|
+
*/
|
|
1076
|
+
getMemories(options: {
|
|
1077
|
+
userId?: string;
|
|
1078
|
+
user_id?: string;
|
|
1079
|
+
customerId?: string;
|
|
1080
|
+
customer_id?: string;
|
|
1081
|
+
mode?: string;
|
|
1082
|
+
conversationId?: string;
|
|
1083
|
+
conversation_id?: string;
|
|
1084
|
+
maxResults?: number;
|
|
1085
|
+
max_results?: number;
|
|
1086
|
+
types?: string[];
|
|
1087
|
+
}): Promise<{
|
|
1088
|
+
results: FlatMemory[];
|
|
1089
|
+
count: number;
|
|
1090
|
+
}>;
|
|
1091
|
+
/** @deprecated Use `client.memories.create()`. */
|
|
1092
|
+
addMemory(options: CreateMemoryOptions): Promise<CreateMemoryResult>;
|
|
1093
|
+
/**
|
|
1094
|
+
* @deprecated Use `client.memories.delete(memoryId)`.
|
|
1095
|
+
*
|
|
1096
|
+
* The `{ userId }` form is gone: it relied on a process-local id list and so
|
|
1097
|
+
* deleted nothing in serverless while reporting success (gotcha G-F).
|
|
1098
|
+
*/
|
|
1099
|
+
deleteMemory(options: {
|
|
1100
|
+
memoryId?: string;
|
|
1101
|
+
memory_id?: string;
|
|
1102
|
+
}): Promise<Json>;
|
|
1103
|
+
/**
|
|
1104
|
+
* Resolve `client_id` and `instance_id` from the API key.
|
|
1105
|
+
*
|
|
1106
|
+
* Mirrors Python's `initialize()`. Calling it is optional here (unlike
|
|
1107
|
+
* Python, which raises "SDK not initialized" from `_ensure_initialized`)
|
|
1108
|
+
* because every HTTP route authenticates on the API key alone. It matters
|
|
1109
|
+
* for the anticipation cache: a bundle shared at client scope is filtered on
|
|
1110
|
+
* `client_id`, and an empty one fails that filter for every bundle. That was
|
|
1111
|
+
* a silent cache-scope bug in Python before whoami bootstrapping existed.
|
|
1112
|
+
*
|
|
1113
|
+
* Best-effort and idempotent. A whoami failure leaves whatever the
|
|
1114
|
+
* constructor resolved and is not fatal.
|
|
1115
|
+
*/
|
|
1116
|
+
initialize(): Promise<void>;
|
|
1117
|
+
/**
|
|
1118
|
+
* @deprecated Use `initialize()`, which is the Python name. `init()` was a
|
|
1119
|
+
* JS-only spelling with no Python counterpart; it now forwards, so a 0.3.x
|
|
1120
|
+
* startup script keeps working.
|
|
1121
|
+
*/
|
|
1122
|
+
init(): Promise<void>;
|
|
1123
|
+
/** The resolved instance id. Empty until `initialize()` resolves it. */
|
|
1124
|
+
get instance_id(): string;
|
|
1125
|
+
/** The resolved client id. Empty until `initialize()` resolves it. */
|
|
1126
|
+
get client_id(): string;
|
|
1127
|
+
/**
|
|
1128
|
+
* Update configuration before `initialize()`.
|
|
1129
|
+
*
|
|
1130
|
+
* Mirrors Python's `configure()`, including its refusal to reconfigure after
|
|
1131
|
+
* initialization: the transport and cache are already built by then and a
|
|
1132
|
+
* half-applied config is worse than a rejected one.
|
|
1133
|
+
*
|
|
1134
|
+
* The Python-only keys (`storage_path`, `cache_backend`,
|
|
1135
|
+
* `session_timeout_minutes`, `logger`) are accepted and ignored rather than
|
|
1136
|
+
* rejected, because this SDK has no SQLite cache backend and no global
|
|
1137
|
+
* logger to swap. Ignoring them keeps a shared config object portable
|
|
1138
|
+
* between the two SDKs.
|
|
1139
|
+
*/
|
|
1140
|
+
configure(options?: ConfigureOptions): void;
|
|
1141
|
+
/**
|
|
1142
|
+
* Fetch and merge context across every scope with an identifier, in one call.
|
|
1143
|
+
*
|
|
1144
|
+
* Mirrors Python's `sdk.fetch()`. The three behaviours worth knowing:
|
|
1145
|
+
*
|
|
1146
|
+
* - Scope fetches run in parallel and a FAILED scope is dropped with a
|
|
1147
|
+
* warning rather than failing the call, so partial context still gets
|
|
1148
|
+
* returned. The one exception is `InvalidInputError`: a bad request must
|
|
1149
|
+
* surface instead of degrading into a silently-empty context.
|
|
1150
|
+
* - `user_id` is threaded into the conversation-scope sub-fetch so the
|
|
1151
|
+
* anticipation cache can apply its per-user filter.
|
|
1152
|
+
* - The summary-mode parameters go ONLY to the user-scope sub-fetch. The
|
|
1153
|
+
* other three routes return 422 for `context_mode="conversation-summary"`,
|
|
1154
|
+
* and that rejection would be swallowed by the drop-failed-scope rule.
|
|
1155
|
+
*/
|
|
1156
|
+
fetch(options?: UnifiedFetchOptions): Promise<UnifiedContext>;
|
|
1157
|
+
/**
|
|
1158
|
+
* An LLM-ready tool definition that fetches Synap context.
|
|
1159
|
+
*
|
|
1160
|
+
* Mirrors Python's `as_tool()`. The scope identifiers are closed over, so
|
|
1161
|
+
* the model cannot choose whose memory to read.
|
|
1162
|
+
*/
|
|
1163
|
+
as_tool(options?: AsToolOptions): ToolDefinition;
|
|
1164
|
+
/**
|
|
1165
|
+
* A read-only diagnostic view of the in-process anticipation cache.
|
|
1166
|
+
*
|
|
1167
|
+
* Mirrors Python's `anticipation_cache_snapshot()`. Returns the same
|
|
1168
|
+
* snake_case shape, since this output gets logged and compared across SDKs.
|
|
1169
|
+
*/
|
|
1170
|
+
anticipation_cache_snapshot(): AnticipationCacheSnapshot;
|
|
1171
|
+
/** Release timers and connections. Safe to call more than once. */
|
|
1172
|
+
shutdown(): Promise<void>;
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
/** Kept in sync with package.json by the release workflow. */
|
|
1176
|
+
declare const SDK_VERSION = "1.0.0-beta.0";
|
|
1177
|
+
|
|
1178
|
+
/**
|
|
1179
|
+
* Synap SDK error taxonomy.
|
|
1180
|
+
*
|
|
1181
|
+
* Mirrors `maximem_synap/models/errors.py` 1:1, including the four
|
|
1182
|
+
* backward-compatibility aliases at the bottom. If you add an error to one
|
|
1183
|
+
* SDK, add it to the other in the same change.
|
|
1184
|
+
*
|
|
1185
|
+
* ## Why every error carries a `.code`
|
|
1186
|
+
*
|
|
1187
|
+
* This package ships dual ESM + CJS. A consumer whose dependency graph pulls
|
|
1188
|
+
* in both formats gets *two* copies of every class in this file, and then:
|
|
1189
|
+
*
|
|
1190
|
+
* try { ... } catch (e) { if (e instanceof SynapError) { ... } }
|
|
1191
|
+
*
|
|
1192
|
+
* silently evaluates to `false` against the copy from the other format. Error
|
|
1193
|
+
* handling stops working and nothing throws to tell you. `.code` is a plain
|
|
1194
|
+
* string, so it is immune. Prefer it at package boundaries:
|
|
1195
|
+
*
|
|
1196
|
+
* if (isSynapError(e) && e.code === 'rate_limit') { ... }
|
|
1197
|
+
*
|
|
1198
|
+
* `Symbol.hasInstance` is also wired up on the base class, so `instanceof`
|
|
1199
|
+
* works across realms too -- but `.code` is the documented contract.
|
|
1200
|
+
*/
|
|
1201
|
+
/** Stable, format-independent discriminators. Never renumber or reuse. */
|
|
1202
|
+
type SynapErrorCode = 'synap_error' | 'transient' | 'permanent' | 'network_timeout' | 'rate_limit' | 'insufficient_credits' | 'service_unavailable' | 'invalid_input' | 'invalid_instance_id' | 'invalid_conversation_id' | 'authentication' | 'context_not_found' | 'conflict' | 'transcript_conflict' | 'session_expired' | 'listening_already_active' | 'listening_not_active' | 'agent_unavailable';
|
|
1203
|
+
interface SynapErrorOptions {
|
|
1204
|
+
correlationId?: string | null;
|
|
1205
|
+
cause?: unknown;
|
|
1206
|
+
}
|
|
1207
|
+
declare class SynapError extends Error {
|
|
1208
|
+
/**
|
|
1209
|
+
* The single declaration site for each subclass's code.
|
|
1210
|
+
*
|
|
1211
|
+
* It is `static` rather than a class field on purpose. Under
|
|
1212
|
+
* `useDefineForClassFields` (the default at our ES2022 target) a class field
|
|
1213
|
+
* is an *instance* property, so it is invisible from the constructor object.
|
|
1214
|
+
* `Symbol.hasInstance` below only has the constructor to work with, so a
|
|
1215
|
+
* field would leave it unable to tell `AuthenticationError` from
|
|
1216
|
+
* `RateLimitError` -- it would report every Synap error as an instance of
|
|
1217
|
+
* every other one.
|
|
1218
|
+
*/
|
|
1219
|
+
static readonly errorCode: SynapErrorCode;
|
|
1220
|
+
/** True for errors where a retry may succeed. Static for the same reason. */
|
|
1221
|
+
static readonly isTransient: boolean;
|
|
1222
|
+
/** Own, enumerable, so logs and JSON.stringify include it. */
|
|
1223
|
+
readonly code: SynapErrorCode;
|
|
1224
|
+
readonly correlationId: string | null;
|
|
1225
|
+
readonly transient: boolean;
|
|
1226
|
+
constructor(message: string, options?: SynapErrorOptions);
|
|
1227
|
+
static [Symbol.hasInstance](instance: unknown): boolean;
|
|
1228
|
+
}
|
|
1229
|
+
/** Type guard that works across ESM/CJS copies and realms. */
|
|
1230
|
+
declare function isSynapError(e: unknown): e is SynapError;
|
|
1231
|
+
declare class SynapTransientError extends SynapError {
|
|
1232
|
+
static readonly errorCode: SynapErrorCode;
|
|
1233
|
+
static readonly isTransient: boolean;
|
|
1234
|
+
}
|
|
1235
|
+
declare class SynapPermanentError extends SynapError {
|
|
1236
|
+
static readonly errorCode: SynapErrorCode;
|
|
1237
|
+
static readonly isTransient: boolean;
|
|
1238
|
+
}
|
|
1239
|
+
declare class NetworkTimeoutError extends SynapTransientError {
|
|
1240
|
+
static readonly errorCode: SynapErrorCode;
|
|
1241
|
+
}
|
|
1242
|
+
declare class RateLimitError extends SynapTransientError {
|
|
1243
|
+
static readonly errorCode: SynapErrorCode;
|
|
1244
|
+
readonly retryAfterSeconds: number | null;
|
|
1245
|
+
constructor(message: string, options?: SynapErrorOptions & {
|
|
1246
|
+
retryAfterSeconds?: number | null;
|
|
1247
|
+
});
|
|
1248
|
+
}
|
|
1249
|
+
declare class ServiceUnavailableError extends SynapTransientError {
|
|
1250
|
+
static readonly errorCode: SynapErrorCode;
|
|
1251
|
+
}
|
|
1252
|
+
declare class AgentUnavailableError extends SynapTransientError {
|
|
1253
|
+
static readonly errorCode: SynapErrorCode;
|
|
1254
|
+
constructor(message?: string, options?: SynapErrorOptions);
|
|
1255
|
+
}
|
|
1256
|
+
/**
|
|
1257
|
+
* The caller's credit wallet cannot cover this request.
|
|
1258
|
+
*
|
|
1259
|
+
* HTTP 402, and gRPC RESOURCE_EXHAUSTED with credit-related trailing metadata.
|
|
1260
|
+
* Permanent by design: retrying without topping up burns quota and never
|
|
1261
|
+
* succeeds. This is the error behind "the agent forgot" reports where retrieval
|
|
1262
|
+
* silently returns nothing.
|
|
1263
|
+
*/
|
|
1264
|
+
declare class InsufficientCreditsError extends SynapPermanentError {
|
|
1265
|
+
static readonly errorCode: SynapErrorCode;
|
|
1266
|
+
readonly balanceCredits: number | null;
|
|
1267
|
+
readonly requiredCredits: number | null;
|
|
1268
|
+
constructor(message: string, options?: SynapErrorOptions & {
|
|
1269
|
+
balanceCredits?: number | null;
|
|
1270
|
+
requiredCredits?: number | null;
|
|
1271
|
+
});
|
|
1272
|
+
}
|
|
1273
|
+
declare class InvalidInputError extends SynapPermanentError {
|
|
1274
|
+
static readonly errorCode: SynapErrorCode;
|
|
1275
|
+
}
|
|
1276
|
+
/**
|
|
1277
|
+
* Raised by `validateInstanceId` before any network call, matching Python's
|
|
1278
|
+
* `utils/validators.py`. The message text is identical in both SDKs.
|
|
1279
|
+
*/
|
|
1280
|
+
declare class InvalidInstanceIdError extends InvalidInputError {
|
|
1281
|
+
static readonly errorCode: SynapErrorCode;
|
|
1282
|
+
}
|
|
1283
|
+
/** See the note on InvalidInstanceIdError. Raised by `validateConversationId`. */
|
|
1284
|
+
declare class InvalidConversationIdError extends InvalidInputError {
|
|
1285
|
+
static readonly errorCode: SynapErrorCode;
|
|
1286
|
+
}
|
|
1287
|
+
declare class AuthenticationError extends SynapPermanentError {
|
|
1288
|
+
static readonly errorCode: SynapErrorCode;
|
|
1289
|
+
}
|
|
1290
|
+
declare class ContextNotFoundError extends SynapPermanentError {
|
|
1291
|
+
static readonly errorCode: SynapErrorCode;
|
|
1292
|
+
}
|
|
1293
|
+
declare class ConflictError extends SynapPermanentError {
|
|
1294
|
+
static readonly errorCode: SynapErrorCode;
|
|
1295
|
+
}
|
|
1296
|
+
declare class TranscriptConflictError extends ConflictError {
|
|
1297
|
+
static readonly errorCode: SynapErrorCode;
|
|
1298
|
+
}
|
|
1299
|
+
declare class SessionExpiredError extends SynapPermanentError {
|
|
1300
|
+
static readonly errorCode: SynapErrorCode;
|
|
1301
|
+
}
|
|
1302
|
+
declare class ListeningAlreadyActiveError extends SynapPermanentError {
|
|
1303
|
+
static readonly errorCode: SynapErrorCode;
|
|
1304
|
+
}
|
|
1305
|
+
declare class ListeningNotActiveError extends SynapPermanentError {
|
|
1306
|
+
static readonly errorCode: SynapErrorCode;
|
|
1307
|
+
}
|
|
1308
|
+
declare const SDKError: typeof SynapError;
|
|
1309
|
+
declare const TransientError: typeof SynapTransientError;
|
|
1310
|
+
declare const PermanentError: typeof SynapPermanentError;
|
|
1311
|
+
declare const ConnectionError: typeof NetworkTimeoutError;
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Scope-aware context fetching.
|
|
1315
|
+
*
|
|
1316
|
+
* Scopes are client > customer > user. `conversation_id` is NOT a tier: it
|
|
1317
|
+
* groups turns within a scope. Passing it narrows an existing scope rather
|
|
1318
|
+
* than selecting a different one.
|
|
1319
|
+
*/
|
|
1320
|
+
|
|
1321
|
+
type Scope = 'user' | 'customer' | 'client' | 'conversation';
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* BM25 scorer for the anticipation cache.
|
|
1325
|
+
*
|
|
1326
|
+
* A faithful port of `maximem_synap/cache/bm25.py`. Every tuned value comes
|
|
1327
|
+
* from the shared behavior contract, so the two implementations cannot drift
|
|
1328
|
+
* on parameters. What they *can* still drift on is arithmetic, which is what
|
|
1329
|
+
* the shared conformance corpus is for.
|
|
1330
|
+
*/
|
|
1331
|
+
declare function stem(word: string): string;
|
|
1332
|
+
/** Tokenize, lowercase, remove stop words, and stem. Alias labels survive whole. */
|
|
1333
|
+
declare function tokenize(text: string | null | undefined): string[];
|
|
1334
|
+
/** Okapi BM25 scorer over a small in-memory corpus. */
|
|
1335
|
+
declare class BM25 {
|
|
1336
|
+
static readonly IDF_FLOOR: number;
|
|
1337
|
+
readonly k1: number;
|
|
1338
|
+
readonly b: number;
|
|
1339
|
+
readonly corpus: readonly (readonly string[])[];
|
|
1340
|
+
readonly docCount: number;
|
|
1341
|
+
readonly avgdl: number;
|
|
1342
|
+
readonly docLens: readonly number[];
|
|
1343
|
+
readonly idf: ReadonlyMap<string, number>;
|
|
1344
|
+
constructor(corpus: readonly (readonly string[])[], k1?: number, b?: number);
|
|
1345
|
+
score(queryTokens: readonly string[], docIdx: number): number;
|
|
1346
|
+
scores(queryTokens: readonly string[]): number[];
|
|
1347
|
+
}
|
|
1348
|
+
|
|
1349
|
+
/**
|
|
1350
|
+
* Loader for the shared SDK behavior contract.
|
|
1351
|
+
*
|
|
1352
|
+
* The values here are tuned against measured eval failures and are shared,
|
|
1353
|
+
* byte-identical, with the Python SDK. They live in data rather than code
|
|
1354
|
+
* specifically so the two SDKs cannot drift. See
|
|
1355
|
+
* `synap/sdk/CONTRACT/README.md`.
|
|
1356
|
+
*
|
|
1357
|
+
* `anticipation.json` is vendored into `src/` by
|
|
1358
|
+
* `synap/sdk/scripts/sync-behavior.sh` and imported (not read from disk) so
|
|
1359
|
+
* that the bundler inlines it. Reading it with `node:fs` at runtime would work
|
|
1360
|
+
* in Node and break in every bundled target: Edge, Workers, and anything under
|
|
1361
|
+
* webpack/turbopack, where `dist/` is rewritten and relative paths do not
|
|
1362
|
+
* survive. It is the same failure mode as `@grpc/proto-loader` reading a
|
|
1363
|
+
* `.proto` off disk (gotcha G-P).
|
|
1364
|
+
*/
|
|
1365
|
+
interface RecallPattern {
|
|
1366
|
+
pattern: string;
|
|
1367
|
+
flags: string;
|
|
1368
|
+
note: string;
|
|
1369
|
+
}
|
|
1370
|
+
interface BehaviorContract {
|
|
1371
|
+
version: number;
|
|
1372
|
+
recall_bypass: {
|
|
1373
|
+
note: string;
|
|
1374
|
+
env_flag: string;
|
|
1375
|
+
default: boolean;
|
|
1376
|
+
patterns: RecallPattern[];
|
|
1377
|
+
};
|
|
1378
|
+
thresholds: {
|
|
1379
|
+
bm25: {
|
|
1380
|
+
value: number;
|
|
1381
|
+
note: string;
|
|
1382
|
+
};
|
|
1383
|
+
novel_term: {
|
|
1384
|
+
value: number;
|
|
1385
|
+
note: string;
|
|
1386
|
+
};
|
|
1387
|
+
min_corpus_for_novel_gate: {
|
|
1388
|
+
value: number;
|
|
1389
|
+
note: string;
|
|
1390
|
+
};
|
|
1391
|
+
effective_floor: {
|
|
1392
|
+
value: number;
|
|
1393
|
+
note: string;
|
|
1394
|
+
};
|
|
1395
|
+
query_token_scale: {
|
|
1396
|
+
value: number;
|
|
1397
|
+
note: string;
|
|
1398
|
+
};
|
|
1399
|
+
};
|
|
1400
|
+
coverage_gate: {
|
|
1401
|
+
note: string;
|
|
1402
|
+
env_flag: string;
|
|
1403
|
+
default: number | null;
|
|
1404
|
+
empty_query_coverage: number;
|
|
1405
|
+
};
|
|
1406
|
+
telemetry: {
|
|
1407
|
+
rejected_items_cap: {
|
|
1408
|
+
value: number;
|
|
1409
|
+
note: string;
|
|
1410
|
+
};
|
|
1411
|
+
content_preview_chars: number;
|
|
1412
|
+
};
|
|
1413
|
+
bm25: {
|
|
1414
|
+
k1: number;
|
|
1415
|
+
b: number;
|
|
1416
|
+
idf_floor: number;
|
|
1417
|
+
min_token_len: number;
|
|
1418
|
+
min_stem_len: number;
|
|
1419
|
+
suffixes: string[];
|
|
1420
|
+
stop_words: string[];
|
|
1421
|
+
alias_token: {
|
|
1422
|
+
pattern: string;
|
|
1423
|
+
note: string;
|
|
1424
|
+
};
|
|
1425
|
+
};
|
|
1426
|
+
}
|
|
1427
|
+
declare const CONTRACT: BehaviorContract;
|
|
1428
|
+
declare const THRESHOLDS: {
|
|
1429
|
+
readonly bm25: number;
|
|
1430
|
+
readonly novelTerm: number;
|
|
1431
|
+
readonly minCorpusForNovelGate: number;
|
|
1432
|
+
/** Lower bound on the derived per-query threshold. */
|
|
1433
|
+
readonly effectiveFloor: number;
|
|
1434
|
+
/** Points of score allowed per query token when deriving the threshold. */
|
|
1435
|
+
readonly queryTokenScale: number;
|
|
1436
|
+
};
|
|
1437
|
+
/** True when any query string looks like an explicit memory-recall ask. */
|
|
1438
|
+
declare function isRecallQuery(searchQuery: readonly (string | null | undefined)[] | null | undefined): boolean;
|
|
1439
|
+
|
|
1440
|
+
/**
|
|
1441
|
+
* @maximem/synap-js-sdk
|
|
1442
|
+
*
|
|
1443
|
+
* Native TypeScript SDK for Synap. No Python runtime required.
|
|
1444
|
+
*/
|
|
1445
|
+
|
|
1446
|
+
/**
|
|
1447
|
+
* The duck-typed contract the TS integrations rely on.
|
|
1448
|
+
*
|
|
1449
|
+
* `synap-mastra`, `synap-eve` and `synap-claude-agent-ts` each redeclare this
|
|
1450
|
+
* shape locally today. Exporting it here means they can `import type` it
|
|
1451
|
+
* instead, so a change to the client's surface breaks their build rather than
|
|
1452
|
+
* their runtime.
|
|
1453
|
+
*/
|
|
1454
|
+
interface SynapSdkLike {
|
|
1455
|
+
user: {
|
|
1456
|
+
context: {
|
|
1457
|
+
fetch: (options?: Record<string, unknown>) => Promise<unknown>;
|
|
1458
|
+
};
|
|
1459
|
+
};
|
|
1460
|
+
customer: {
|
|
1461
|
+
context: {
|
|
1462
|
+
fetch: (options?: Record<string, unknown>) => Promise<unknown>;
|
|
1463
|
+
};
|
|
1464
|
+
};
|
|
1465
|
+
client: {
|
|
1466
|
+
context: {
|
|
1467
|
+
fetch: (options?: Record<string, unknown>) => Promise<unknown>;
|
|
1468
|
+
};
|
|
1469
|
+
};
|
|
1470
|
+
memories: {
|
|
1471
|
+
create: (options: {
|
|
1472
|
+
document: string;
|
|
1473
|
+
} & Record<string, unknown>) => Promise<unknown>;
|
|
1474
|
+
};
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
export { AgentUnavailableError, type AnthropicToolDefinition, AnticipationCacheSnapshot, type AsToolOptions, AuthenticationError, BM25, CONTRACT, type CacheNamespace, type CacheStats, type CompactOptions, type CompactionCallback, type ConfigureOptions, ConflictError, ConnectionError, type ContextMetadata, ContextNotFoundError, type ConversationContext, type ConversationNamespace, type CreateFromFileOptions, type CreateMemoryOptions, type CreateMemoryResult, type Credentials, type CreditsNamespace, DEFAULT_BASE_URL, DEFAULT_DOCUMENT_TYPE, DEFAULT_INGEST_MODE, DEFAULT_RETRY_POLICY, DEFAULT_TIMEOUTS, DOCUMENT_TYPES, type DocumentType, ENDPOINTS, type Emotion, type EndpointName, type EndpointSpec, type Episode, type EstimateOptions, type Fact, type FetchOptions, type FlatMemory, type FormatOptions, HttpTransport, type HttpTransportOptions, INGEST_MODES, ITEM_COLLECTIONS, type IngestMode, type IngestTranscriptOptions, type InstanceNamespace, InsufficientCreditsError, InvalidConversationIdError, InvalidInputError, InvalidInstanceIdError, type ItemCollection, type Json, type ListenOptions, ListeningAlreadyActiveError, ListeningNotActiveError, type MemoriesInterface, NetworkTimeoutError, type NormalisedContext, type OpenAiToolDefinition, PermanentError, type Preference, RateLimitError, type RawContext, type RawContextItem, type RawConversationContext, type RecordMessageOptions, type RecordThinkingOptions, type RequestOptions, type RetryPolicy, SDKError, SDK_VERSION, type Scope, type SendMessageOptions, ServiceUnavailableError, SessionExpiredError, SynapClient, type SynapClientOptions, SynapError, type SynapErrorCode, type SynapErrorOptions, SynapPermanentError, type SynapSdkLike, SynapTransientError, THRESHOLDS, type TemporalEvent, type TemporalFields, type TimeoutConfig, type ToolDefinition, type ToolHandler, type ToolScope, type ToolStyle, TranscriptConflictError, type TranscriptTurn, TransientError, type UnifiedContext, type UnifiedFetchOptions, type UpdateMemoryOptions, type UserNamespace, type WaitOptions, type WriteInvalidator, flattenContextItems, formatForPrompt, isOutcomeUnknown, isRecallQuery, isSynapError, mergeScopeResults, resolvePath, shouldRetry, stem, tokenize };
|