10xgraph-client 0.6.0 → 1.0.0-rc.2
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/CHANGELOG.md +207 -0
- package/README.md +11 -5
- package/dist/agent.d.ts +17 -5
- package/dist/agent.d.ts.map +1 -1
- package/dist/cjs/agent.d.ts +33 -0
- package/dist/cjs/client.d.ts +533 -0
- package/dist/cjs/compat.d.ts +27 -0
- package/dist/cjs/endpoints/addThreadMessages.d.ts +25 -0
- package/dist/cjs/endpoints/clearThreadState.d.ts +14 -0
- package/dist/cjs/endpoints/deleteFile.d.ts +13 -0
- package/dist/cjs/endpoints/deleteMemory.d.ts +18 -0
- package/dist/cjs/endpoints/deleteThread.d.ts +18 -0
- package/dist/cjs/endpoints/deleteThreadMessage.d.ts +19 -0
- package/dist/cjs/endpoints/files.d.ts +115 -0
- package/dist/cjs/endpoints/fixGraph.d.ts +33 -0
- package/dist/cjs/endpoints/forgetMemories.d.ts +21 -0
- package/dist/cjs/endpoints/getMemory.d.ts +18 -0
- package/dist/cjs/endpoints/graph.d.ts +50 -0
- package/dist/cjs/endpoints/graphTools.d.ts +31 -0
- package/dist/cjs/endpoints/invoke.d.ts +66 -0
- package/dist/cjs/endpoints/listMemories.d.ts +24 -0
- package/dist/cjs/endpoints/metadata.d.ts +5 -0
- package/dist/cjs/endpoints/observability.d.ts +111 -0
- package/dist/cjs/endpoints/ping.d.ts +9 -0
- package/dist/cjs/endpoints/realtime.d.ts +154 -0
- package/dist/cjs/endpoints/searchMemory.d.ts +56 -0
- package/dist/cjs/endpoints/stateSchema.d.ts +49 -0
- package/dist/cjs/endpoints/stopGraph.d.ts +35 -0
- package/dist/cjs/endpoints/storeMemory.d.ts +32 -0
- package/dist/cjs/endpoints/stream.d.ts +67 -0
- package/dist/cjs/endpoints/threadDetails.d.ts +18 -0
- package/dist/cjs/endpoints/threadMessage.d.ts +16 -0
- package/dist/cjs/endpoints/threadMessages.d.ts +28 -0
- package/dist/cjs/endpoints/threadState.d.ts +13 -0
- package/dist/cjs/endpoints/threads.d.ts +35 -0
- package/dist/cjs/endpoints/updateMemory.d.ts +20 -0
- package/dist/cjs/endpoints/updateThreadMessageFeedback.d.ts +19 -0
- package/dist/cjs/endpoints/updateThreadState.d.ts +22 -0
- package/dist/cjs/endpoints/wsStream.d.ts +34 -0
- package/dist/cjs/errors.d.ts +212 -0
- package/dist/cjs/index.d.ts +41 -0
- package/dist/cjs/interrupt.d.ts +45 -0
- package/dist/cjs/message.d.ts +173 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/request.d.ts +60 -0
- package/dist/cjs/tools.d.ts +80 -0
- package/dist/cjs/ws.d.ts +47 -0
- package/dist/client.d.ts +95 -40
- package/dist/client.d.ts.map +1 -1
- package/dist/endpoints/addThreadMessages.d.ts +4 -0
- package/dist/endpoints/addThreadMessages.d.ts.map +1 -1
- package/dist/endpoints/clearThreadState.d.ts.map +1 -1
- package/dist/endpoints/deleteFile.d.ts +14 -0
- package/dist/endpoints/deleteFile.d.ts.map +1 -0
- package/dist/endpoints/deleteMemory.d.ts.map +1 -1
- package/dist/endpoints/deleteThread.d.ts.map +1 -1
- package/dist/endpoints/deleteThreadMessage.d.ts.map +1 -1
- package/dist/endpoints/files.d.ts +33 -0
- package/dist/endpoints/files.d.ts.map +1 -1
- package/dist/endpoints/fixGraph.d.ts +8 -3
- package/dist/endpoints/fixGraph.d.ts.map +1 -1
- package/dist/endpoints/forgetMemories.d.ts.map +1 -1
- package/dist/endpoints/getMemory.d.ts.map +1 -1
- package/dist/endpoints/graph.d.ts +20 -8
- package/dist/endpoints/graph.d.ts.map +1 -1
- package/dist/endpoints/graphTools.d.ts.map +1 -1
- package/dist/endpoints/invoke.d.ts +8 -0
- package/dist/endpoints/invoke.d.ts.map +1 -1
- package/dist/endpoints/listMemories.d.ts +6 -0
- package/dist/endpoints/listMemories.d.ts.map +1 -1
- package/dist/endpoints/observability.d.ts +54 -0
- package/dist/endpoints/observability.d.ts.map +1 -1
- package/dist/endpoints/ping.d.ts.map +1 -1
- package/dist/endpoints/realtime.d.ts +25 -4
- package/dist/endpoints/realtime.d.ts.map +1 -1
- package/dist/endpoints/searchMemory.d.ts.map +1 -1
- package/dist/endpoints/stateSchema.d.ts.map +1 -1
- package/dist/endpoints/stopGraph.d.ts +13 -3
- package/dist/endpoints/stopGraph.d.ts.map +1 -1
- package/dist/endpoints/storeMemory.d.ts.map +1 -1
- package/dist/endpoints/stream.d.ts +8 -0
- package/dist/endpoints/stream.d.ts.map +1 -1
- package/dist/endpoints/threadDetails.d.ts.map +1 -1
- package/dist/endpoints/threadMessage.d.ts.map +1 -1
- package/dist/endpoints/threadMessages.d.ts +6 -0
- package/dist/endpoints/threadMessages.d.ts.map +1 -1
- package/dist/endpoints/threadState.d.ts.map +1 -1
- package/dist/endpoints/threads.d.ts +6 -0
- package/dist/endpoints/threads.d.ts.map +1 -1
- package/dist/endpoints/updateMemory.d.ts.map +1 -1
- package/dist/endpoints/updateThreadMessageFeedback.d.ts +20 -0
- package/dist/endpoints/updateThreadMessageFeedback.d.ts.map +1 -0
- package/dist/endpoints/updateThreadState.d.ts +6 -1
- package/dist/endpoints/updateThreadState.d.ts.map +1 -1
- package/dist/endpoints/wsStream.d.ts +2 -0
- package/dist/endpoints/wsStream.d.ts.map +1 -1
- package/dist/errors.d.ts +60 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1742 -1217
- package/dist/index.js.map +1 -1
- package/dist/interrupt.d.ts +46 -0
- package/dist/interrupt.d.ts.map +1 -0
- package/dist/request.d.ts +28 -0
- package/dist/request.d.ts.map +1 -1
- package/dist/tools.d.ts +14 -0
- package/dist/tools.d.ts.map +1 -1
- package/package.json +11 -6
- package/src/agent.ts +17 -4
- package/src/client.ts +248 -128
- package/src/endpoints/addThreadMessages.ts +15 -10
- package/src/endpoints/clearThreadState.ts +19 -20
- package/src/endpoints/deleteFile.ts +65 -0
- package/src/endpoints/deleteMemory.ts +9 -13
- package/src/endpoints/deleteThread.ts +9 -13
- package/src/endpoints/deleteThreadMessage.ts +9 -13
- package/src/endpoints/files.ts +164 -131
- package/src/endpoints/fixGraph.ts +15 -16
- package/src/endpoints/forgetMemories.ts +44 -60
- package/src/endpoints/getMemory.ts +9 -9
- package/src/endpoints/graph.ts +28 -21
- package/src/endpoints/graphTools.ts +7 -13
- package/src/endpoints/invoke.ts +105 -84
- package/src/endpoints/listMemories.ts +18 -13
- package/src/endpoints/observability.ts +77 -34
- package/src/endpoints/ping.ts +7 -13
- package/src/endpoints/realtime.ts +101 -39
- package/src/endpoints/searchMemory.ts +19 -13
- package/src/endpoints/stateSchema.ts +7 -13
- package/src/endpoints/stopGraph.ts +20 -16
- package/src/endpoints/storeMemory.ts +7 -8
- package/src/endpoints/stream.ts +179 -61
- package/src/endpoints/threadDetails.ts +9 -14
- package/src/endpoints/threadMessage.ts +9 -9
- package/src/endpoints/threadMessages.ts +15 -9
- package/src/endpoints/threadState.ts +19 -20
- package/src/endpoints/threads.ts +13 -12
- package/src/endpoints/updateMemory.ts +9 -9
- package/src/endpoints/updateThreadMessageFeedback.ts +80 -0
- package/src/endpoints/updateThreadState.ts +28 -22
- package/src/endpoints/wsStream.ts +167 -42
- package/src/errors.ts +332 -93
- package/src/index.ts +9 -0
- package/src/interrupt.ts +60 -0
- package/src/request.ts +134 -0
- package/src/tools.ts +95 -0
|
@@ -22,11 +22,15 @@ export interface RealtimeVADConfig {
|
|
|
22
22
|
|
|
23
23
|
export interface RealtimeInit {
|
|
24
24
|
/**
|
|
25
|
-
* e.g. "gemini-
|
|
25
|
+
* e.g. "gemini-3.8-live". Honoured only when the server lists it in
|
|
26
26
|
* `websocket.realtime_models`; otherwise the agent's own model is used.
|
|
27
27
|
*/
|
|
28
28
|
model?: string;
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Omit to let the server create the thread; the id arrives in the `session_started` event and
|
|
31
|
+
* is read from `session.threadId`. Pass an id to continue a thread (the server must allow it:
|
|
32
|
+
* under the default `runs.thread_ids: "server"` it must be one the server already knows).
|
|
33
|
+
*/
|
|
30
34
|
thread_id?: string;
|
|
31
35
|
voice?: string;
|
|
32
36
|
modalities?: ResponseModality | ResponseModality[];
|
|
@@ -40,6 +44,7 @@ export interface RealtimeInit {
|
|
|
40
44
|
|
|
41
45
|
/** Downstream JSON events. Audio arrives separately as binary via the `audio` channel. */
|
|
42
46
|
export type RealtimeEvent =
|
|
47
|
+
| { type: 'session_started'; thread_id: string }
|
|
43
48
|
| { type: 'input_transcript'; text: string; finished: boolean }
|
|
44
49
|
| { type: 'output_transcript'; text: string; finished: boolean }
|
|
45
50
|
| { type: 'tool_call'; id: string; name: string; args: Record<string, unknown> }
|
|
@@ -68,7 +73,11 @@ export interface RealtimeOptions {
|
|
|
68
73
|
onError?: (e: Extract<RealtimeEvent, { type: 'error' }>) => void;
|
|
69
74
|
}
|
|
70
75
|
|
|
71
|
-
export type RealtimeContext = RequestContext &
|
|
76
|
+
export type RealtimeContext = RequestContext &
|
|
77
|
+
WsAuthContext & {
|
|
78
|
+
/** Resolves the current bearer token; called on every (re)connect so a refreshed token is used. */
|
|
79
|
+
getAuthToken?: () => string | null | undefined;
|
|
80
|
+
};
|
|
72
81
|
|
|
73
82
|
// ── Lifecycle/event channels the emitter understands ─────────────────────────
|
|
74
83
|
type ChannelMap = {
|
|
@@ -88,24 +97,8 @@ type ChannelName = keyof ChannelMap;
|
|
|
88
97
|
// fully typed via ChannelMap[K]; this only avoids the unsafe `Function` type.
|
|
89
98
|
type ChannelListener = (...args: never[]) => void;
|
|
90
99
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (c?.randomUUID) {
|
|
94
|
-
return c.randomUUID();
|
|
95
|
-
}
|
|
96
|
-
// Fallback: timestamp-free, index-free pseudo-id is not required here because a
|
|
97
|
-
// dropped session reuses this same id; uniqueness across sessions is enough.
|
|
98
|
-
return 'rt-' + Math.abs(hashString(String(Date.now()))).toString(36);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function hashString(s: string): number {
|
|
102
|
-
let h = 0;
|
|
103
|
-
for (let i = 0; i < s.length; i++) {
|
|
104
|
-
h = (h << 5) - h + s.charCodeAt(i);
|
|
105
|
-
h |= 0;
|
|
106
|
-
}
|
|
107
|
-
return h;
|
|
108
|
-
}
|
|
100
|
+
/** How long a connection must stay open before the reconnect budget is restored. */
|
|
101
|
+
const STABLE_CONNECTION_MS = 10_000;
|
|
109
102
|
|
|
110
103
|
/** Normalize an incoming binary frame (ArrayBuffer / typed array / Buffer) to Uint8Array. */
|
|
111
104
|
function toUint8(data: unknown): Uint8Array | null {
|
|
@@ -127,7 +120,11 @@ function toUint8(data: unknown): Uint8Array | null {
|
|
|
127
120
|
* Mic capture and audio playback are the caller's responsibility.
|
|
128
121
|
*/
|
|
129
122
|
export class RealtimeSession {
|
|
130
|
-
|
|
123
|
+
/**
|
|
124
|
+
* The thread this session runs on: the caller's `thread_id`, or the id the server created.
|
|
125
|
+
* `null` until the `session_started` event arrives, when the caller gave none.
|
|
126
|
+
*/
|
|
127
|
+
threadId: string | null;
|
|
131
128
|
resumptionHandle: string | null = null;
|
|
132
129
|
ready: Promise<void>;
|
|
133
130
|
|
|
@@ -141,12 +138,15 @@ export class RealtimeSession {
|
|
|
141
138
|
private closedByUser = false;
|
|
142
139
|
private fatal = false;
|
|
143
140
|
private reconnectAttempts = 0;
|
|
141
|
+
private reconnectTimer: ReturnType<typeof setTimeout> | undefined;
|
|
142
|
+
private stableTimer: ReturnType<typeof setTimeout> | undefined;
|
|
144
143
|
private readonly reconnectCfg: Required<RealtimeReconnectOptions>;
|
|
145
144
|
|
|
146
145
|
constructor(ctx: RealtimeContext, init: RealtimeInit, options?: RealtimeOptions) {
|
|
147
146
|
this.ctx = ctx;
|
|
148
|
-
this.threadId = init.thread_id ??
|
|
149
|
-
this.init = { ...init
|
|
147
|
+
this.threadId = init.thread_id ?? null;
|
|
148
|
+
this.init = { ...init };
|
|
149
|
+
if (this.threadId === null) delete this.init.thread_id;
|
|
150
150
|
|
|
151
151
|
this.reconnectCfg = {
|
|
152
152
|
enabled: options?.reconnect?.enabled ?? true,
|
|
@@ -164,12 +164,21 @@ export class RealtimeSession {
|
|
|
164
164
|
this.rejectReady = reject;
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
+
// The events API invites callers not to await `ready`; a failed connection must not
|
|
168
|
+
// become an unhandled rejection that ends the process. Awaiting it still rejects.
|
|
169
|
+
this.ready.catch(() => {});
|
|
170
|
+
|
|
167
171
|
this.connect();
|
|
168
172
|
}
|
|
169
173
|
|
|
170
174
|
// ── Public send API ─────────────────────────────────────────────────────────
|
|
175
|
+
/**
|
|
176
|
+
* Frames are dropped unless the socket is open; await `session.ready` (or the `open`
|
|
177
|
+
* event) before sending, so mic callbacks that fire early do not throw.
|
|
178
|
+
*/
|
|
171
179
|
sendAudio(pcm16: Uint8Array | ArrayBuffer): void {
|
|
172
|
-
this.ws
|
|
180
|
+
const ws = this.ws;
|
|
181
|
+
if (ws && ws.readyState === 1) ws.send(pcm16 as ArrayBuffer);
|
|
173
182
|
}
|
|
174
183
|
sendText(text: string): void {
|
|
175
184
|
this.sendControl({ type: 'text', text });
|
|
@@ -182,6 +191,8 @@ export class RealtimeSession {
|
|
|
182
191
|
}
|
|
183
192
|
close(): void {
|
|
184
193
|
this.closedByUser = true;
|
|
194
|
+
this.clearTimers();
|
|
195
|
+
// A close frame only goes out on an open socket; a connecting one is just closed.
|
|
185
196
|
this.sendControl({ type: 'close' });
|
|
186
197
|
const ws = this.ws;
|
|
187
198
|
if (ws && (ws.readyState === 0 || ws.readyState === 1)) {
|
|
@@ -212,14 +223,23 @@ export class RealtimeSession {
|
|
|
212
223
|
}
|
|
213
224
|
|
|
214
225
|
private sendControl(frame: Record<string, unknown>): void {
|
|
215
|
-
this.ws
|
|
226
|
+
const ws = this.ws;
|
|
227
|
+
if (ws && ws.readyState === 1) ws.send(JSON.stringify(frame));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
private clearTimers(): void {
|
|
231
|
+
if (this.reconnectTimer !== undefined) clearTimeout(this.reconnectTimer);
|
|
232
|
+
if (this.stableTimer !== undefined) clearTimeout(this.stableTimer);
|
|
233
|
+
this.reconnectTimer = undefined;
|
|
234
|
+
this.stableTimer = undefined;
|
|
216
235
|
}
|
|
217
236
|
|
|
218
237
|
private connect(): void {
|
|
219
238
|
const url = buildWsUrl(this.ctx, '/v1/graph/live');
|
|
220
239
|
if (this.ctx.debug) console.debug('TenxGraphClient [realtime]: connecting to', url);
|
|
221
240
|
|
|
222
|
-
const
|
|
241
|
+
const getToken = this.ctx.getAuthToken;
|
|
242
|
+
const ws = openWebSocket(url, getToken ? { ...this.ctx, authToken: getToken() } : this.ctx);
|
|
223
243
|
try {
|
|
224
244
|
// Receive audio as ArrayBuffer rather than Blob (browser default is "blob").
|
|
225
245
|
(ws as { binaryType?: string }).binaryType = 'arraybuffer';
|
|
@@ -236,6 +256,13 @@ export class RealtimeSession {
|
|
|
236
256
|
this.resolveReady();
|
|
237
257
|
}
|
|
238
258
|
this.emit('open');
|
|
259
|
+
// The attempt budget is restored only after the link has stayed up for a while, so a
|
|
260
|
+
// server that accepts and drops at once cannot keep resetting it.
|
|
261
|
+
if (this.stableTimer !== undefined) clearTimeout(this.stableTimer);
|
|
262
|
+
this.stableTimer = setTimeout(() => {
|
|
263
|
+
this.stableTimer = undefined;
|
|
264
|
+
this.reconnectAttempts = 0;
|
|
265
|
+
}, STABLE_CONNECTION_MS);
|
|
239
266
|
});
|
|
240
267
|
|
|
241
268
|
ws.addEventListener('message', (event: MessageEvent) => {
|
|
@@ -246,8 +273,24 @@ export class RealtimeSession {
|
|
|
246
273
|
ws.addEventListener('close', (event: CloseEvent) => {
|
|
247
274
|
if (this.ws !== ws) return; // stale socket from a previous connection; ignore
|
|
248
275
|
const code = event?.code ?? 1000;
|
|
276
|
+
if (this.stableTimer !== undefined) clearTimeout(this.stableTimer);
|
|
277
|
+
this.stableTimer = undefined;
|
|
249
278
|
this.emit('close', code);
|
|
250
|
-
|
|
279
|
+
// 1008 is a policy violation (for example an expired or rejected token): retrying
|
|
280
|
+
// with the same credentials cannot succeed.
|
|
281
|
+
if (code === 1008 && !this.closedByUser && !this.fatal) {
|
|
282
|
+
this.fatal = true;
|
|
283
|
+
const failure = {
|
|
284
|
+
type: 'error' as const,
|
|
285
|
+
code: 'policy_violation',
|
|
286
|
+
message: 'Realtime connection closed by the server (1008, policy violation)',
|
|
287
|
+
fatal: true,
|
|
288
|
+
};
|
|
289
|
+
this.emit('error', failure);
|
|
290
|
+
this.emit('event', failure);
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
this.maybeReconnect(code);
|
|
251
294
|
});
|
|
252
295
|
|
|
253
296
|
ws.addEventListener('error', () => {
|
|
@@ -273,6 +316,9 @@ export class RealtimeSession {
|
|
|
273
316
|
if (this.ctx.debug) console.warn('TenxGraphClient [realtime]: bad JSON frame', data);
|
|
274
317
|
return;
|
|
275
318
|
}
|
|
319
|
+
if (parsed.type === 'session_started' && parsed.thread_id) {
|
|
320
|
+
this.threadId = parsed.thread_id;
|
|
321
|
+
}
|
|
276
322
|
if (parsed.type === 'session_update') {
|
|
277
323
|
this.resumptionHandle = parsed.resumption_handle ?? this.resumptionHandle;
|
|
278
324
|
}
|
|
@@ -284,7 +330,7 @@ export class RealtimeSession {
|
|
|
284
330
|
this.emit(parsed.type as ChannelName, parsed as never);
|
|
285
331
|
}
|
|
286
332
|
|
|
287
|
-
private maybeReconnect(): void {
|
|
333
|
+
private maybeReconnect(closeCode?: number): void {
|
|
288
334
|
if (this.closedByUser || this.fatal || !this.reconnectCfg.enabled) {
|
|
289
335
|
return;
|
|
290
336
|
}
|
|
@@ -303,24 +349,40 @@ export class RealtimeSession {
|
|
|
303
349
|
}
|
|
304
350
|
this.reconnectAttempts += 1;
|
|
305
351
|
const attempt = this.reconnectAttempts;
|
|
306
|
-
|
|
307
|
-
|
|
352
|
+
// 1013 means the server is overloaded: go straight to the longest delay. Jitter keeps
|
|
353
|
+
// many clients from retrying in step.
|
|
354
|
+
const backoff =
|
|
355
|
+
closeCode === 1013
|
|
356
|
+
? this.reconnectCfg.maxDelay
|
|
357
|
+
: Math.min(this.reconnectCfg.baseDelay * 2 ** (attempt - 1), this.reconnectCfg.maxDelay);
|
|
358
|
+
const delayMs = backoff * 1000 * (0.5 + Math.random() * 0.5);
|
|
308
359
|
this.emit('reconnecting', attempt);
|
|
309
|
-
setTimeout(() =>
|
|
360
|
+
this.reconnectTimer = setTimeout(() => {
|
|
361
|
+
this.reconnectTimer = undefined;
|
|
362
|
+
this.reconnect();
|
|
363
|
+
}, delayMs);
|
|
310
364
|
}
|
|
311
365
|
|
|
312
366
|
private reconnect(): void {
|
|
367
|
+
if (this.closedByUser) return;
|
|
313
368
|
// Forward the latest resumption handle so the provider can resume server-side.
|
|
314
369
|
this.init = {
|
|
315
370
|
...this.init,
|
|
316
|
-
|
|
371
|
+
// The server-given id, so the same thread continues; none yet means the first connect
|
|
372
|
+
// never got `session_started`, and the server makes a new one.
|
|
373
|
+
...(this.threadId ? { thread_id: this.threadId } : {}),
|
|
317
374
|
...(this.resumptionHandle ? { resumption_handle: this.resumptionHandle } : {}),
|
|
318
375
|
};
|
|
319
|
-
|
|
320
|
-
this.
|
|
321
|
-
this.emit('reconnected')
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
376
|
+
try {
|
|
377
|
+
this.connect();
|
|
378
|
+
this.ws?.addEventListener('open', () => this.emit('reconnected'), {
|
|
379
|
+
once: true,
|
|
380
|
+
} as AddEventListenerOptions);
|
|
381
|
+
} catch (err) {
|
|
382
|
+
// The socket constructor threw inside a timer; count it as a failed attempt instead
|
|
383
|
+
// of letting it escape as an uncaught exception.
|
|
384
|
+
if (this.ctx.debug) console.warn('TenxGraphClient [realtime]: reconnect failed', err);
|
|
385
|
+
this.maybeReconnect();
|
|
386
|
+
}
|
|
325
387
|
}
|
|
326
388
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ResponseMetadata } from './metadata.js';
|
|
2
2
|
import { createErrorFromResponse } from '../errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
buildHeaders,
|
|
5
|
+
getRequestCredentials,
|
|
6
|
+
RequestContext,
|
|
7
|
+
fetchWithTimeout,
|
|
8
|
+
} from '../request.js';
|
|
4
9
|
import { MemoryType } from './storeMemory.js';
|
|
5
10
|
|
|
6
11
|
export interface SearchMemoryContext extends RequestContext {}
|
|
@@ -70,38 +75,39 @@ export async function searchMemory(
|
|
|
70
75
|
console.debug('TenxGraphClient: Searching memories with query:', request.query);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
|
-
const controller = new AbortController();
|
|
74
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
75
|
-
|
|
76
78
|
const url = `${context.baseUrl}/v1/store/search`;
|
|
77
79
|
|
|
78
|
-
// Prepare request body
|
|
79
|
-
|
|
80
|
+
// Prepare request body. memory_type, category and score_threshold have no default:
|
|
81
|
+
// when unset they are omitted so the server applies no filter on them.
|
|
82
|
+
const body: Record<string, unknown> = {
|
|
80
83
|
config: request.config || {},
|
|
81
84
|
options: request.options || {},
|
|
82
85
|
query: request.query,
|
|
83
|
-
memory_type: request.memory_type || MemoryType.EPISODIC,
|
|
84
|
-
category: request.category || '',
|
|
85
86
|
limit: request.limit !== undefined ? request.limit : 10,
|
|
86
|
-
score_threshold: request.score_threshold !== undefined ? request.score_threshold : 0,
|
|
87
87
|
filters: request.filters || {},
|
|
88
88
|
retrieval_strategy: request.retrieval_strategy || RetrievalStrategy.SIMILARITY,
|
|
89
89
|
distance_metric: request.distance_metric || DistanceMetric.COSINE,
|
|
90
90
|
max_tokens: request.max_tokens !== undefined ? request.max_tokens : 4000,
|
|
91
91
|
};
|
|
92
|
+
if (request.memory_type !== undefined && request.memory_type !== null) {
|
|
93
|
+
body.memory_type = request.memory_type;
|
|
94
|
+
}
|
|
95
|
+
if (request.category !== undefined && request.category !== null) {
|
|
96
|
+
body.category = request.category;
|
|
97
|
+
}
|
|
98
|
+
if (request.score_threshold !== undefined && request.score_threshold !== null) {
|
|
99
|
+
body.score_threshold = request.score_threshold;
|
|
100
|
+
}
|
|
92
101
|
|
|
93
|
-
const response = await
|
|
102
|
+
const response = await fetchWithTimeout(context, url, {
|
|
94
103
|
method: 'POST',
|
|
95
104
|
headers: buildHeaders(context as RequestContext, {
|
|
96
105
|
'Content-Type': 'application/json',
|
|
97
106
|
}),
|
|
98
107
|
...getRequestCredentials(context as RequestContext),
|
|
99
108
|
body: JSON.stringify(body),
|
|
100
|
-
signal: controller.signal,
|
|
101
109
|
});
|
|
102
110
|
|
|
103
|
-
clearTimeout(timeoutId);
|
|
104
|
-
|
|
105
111
|
if (!response.ok) {
|
|
106
112
|
console.warn(`TenxGraphClient: Search memory failed with HTTP ${response.status}`);
|
|
107
113
|
const error = await createErrorFromResponse(
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ResponseMetadata } from './metadata.js';
|
|
2
2
|
import { createErrorFromResponse } from '../errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
buildHeaders,
|
|
5
|
+
getRequestCredentials,
|
|
6
|
+
RequestContext,
|
|
7
|
+
fetchWithTimeout,
|
|
8
|
+
} from '../request.js';
|
|
4
9
|
|
|
5
10
|
export interface StateSchemaContext extends RequestContext {}
|
|
6
11
|
|
|
@@ -57,21 +62,15 @@ export async function stateSchema(context: StateSchemaContext): Promise<StateSch
|
|
|
57
62
|
console.debug('TenxGraphClient: Fetching state schema from', context.baseUrl);
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
const
|
|
61
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
62
|
-
|
|
63
|
-
const response = await fetch(`${context.baseUrl}/v1/graph:StateSchema`, {
|
|
65
|
+
const response = await fetchWithTimeout(context, `${context.baseUrl}/v1/graph:StateSchema`, {
|
|
64
66
|
method: 'GET',
|
|
65
67
|
headers: buildHeaders(context as RequestContext, {
|
|
66
68
|
'Content-Type': 'application/json',
|
|
67
69
|
accept: 'application/json',
|
|
68
70
|
}),
|
|
69
71
|
...getRequestCredentials(context as RequestContext),
|
|
70
|
-
signal: controller.signal,
|
|
71
72
|
});
|
|
72
73
|
|
|
73
|
-
clearTimeout(timeoutId);
|
|
74
|
-
|
|
75
74
|
if (!response.ok) {
|
|
76
75
|
console.warn(`TenxGraphClient: State schema fetch failed with HTTP ${response.status}`);
|
|
77
76
|
const error = await createErrorFromResponse(
|
|
@@ -95,11 +94,6 @@ export async function stateSchema(context: StateSchemaContext): Promise<StateSch
|
|
|
95
94
|
console.debug('TenxGraphClient: State schema fetch failed:', error);
|
|
96
95
|
}
|
|
97
96
|
|
|
98
|
-
if ((error as Error).name === 'AbortError') {
|
|
99
|
-
console.warn(`TenxGraphClient: State schema fetch timeout after ${context.timeout}ms`);
|
|
100
|
-
throw new Error(`Request timeout after ${context.timeout}ms`);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
97
|
console.error('TenxGraphClient: State schema fetch failed:', error);
|
|
104
98
|
throw error;
|
|
105
99
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ResponseMetadata } from './metadata.js';
|
|
2
2
|
import { createErrorFromResponse } from '../errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
buildHeaders,
|
|
5
|
+
getRequestCredentials,
|
|
6
|
+
RequestContext,
|
|
7
|
+
fetchWithTimeout,
|
|
8
|
+
} from '../request.js';
|
|
4
9
|
|
|
5
10
|
export interface StopGraphContext extends RequestContext {}
|
|
6
11
|
|
|
@@ -11,9 +16,19 @@ export interface StopGraphRequest {
|
|
|
11
16
|
|
|
12
17
|
export interface StopGraphResponse {
|
|
13
18
|
data: {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
/** False when the thread has no checkpointer or no saved state. */
|
|
20
|
+
ok: boolean;
|
|
21
|
+
/** True when a run was active and a stop was requested. */
|
|
22
|
+
running?: boolean;
|
|
23
|
+
/** Why nothing was stopped, e.g. 'no-checkpointer' or 'no-state'. */
|
|
24
|
+
reason?: string;
|
|
25
|
+
/** @deprecated The server never sends this field. Use `ok`. */
|
|
26
|
+
success?: boolean;
|
|
27
|
+
/** @deprecated The server never sends this field. */
|
|
28
|
+
message?: string;
|
|
29
|
+
/** @deprecated The server never sends this field. */
|
|
30
|
+
thread_id?: string;
|
|
31
|
+
/** @deprecated The server never sends this field. */
|
|
17
32
|
stopped_at?: string;
|
|
18
33
|
};
|
|
19
34
|
metadata: ResponseMetadata;
|
|
@@ -35,10 +50,7 @@ export async function stopGraph(
|
|
|
35
50
|
console.debug('TenxGraphClient: Stopping graph execution for thread:', request.thread_id);
|
|
36
51
|
}
|
|
37
52
|
|
|
38
|
-
const
|
|
39
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
40
|
-
|
|
41
|
-
const response = await fetch(`${context.baseUrl}/v1/graph/stop`, {
|
|
53
|
+
const response = await fetchWithTimeout(context, `${context.baseUrl}/v1/graph/stop`, {
|
|
42
54
|
method: 'POST',
|
|
43
55
|
headers: buildHeaders(context as RequestContext, {
|
|
44
56
|
'Content-Type': 'application/json',
|
|
@@ -46,11 +58,8 @@ export async function stopGraph(
|
|
|
46
58
|
}),
|
|
47
59
|
...getRequestCredentials(context as RequestContext),
|
|
48
60
|
body: JSON.stringify(request),
|
|
49
|
-
signal: controller.signal,
|
|
50
61
|
});
|
|
51
62
|
|
|
52
|
-
clearTimeout(timeoutId);
|
|
53
|
-
|
|
54
63
|
if (!response.ok) {
|
|
55
64
|
console.warn(`TenxGraphClient: Stop graph failed with HTTP ${response.status}`);
|
|
56
65
|
const error = await createErrorFromResponse(
|
|
@@ -74,11 +83,6 @@ export async function stopGraph(
|
|
|
74
83
|
console.debug('TenxGraphClient: Stop graph failed:', error);
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
if ((error as Error).name === 'AbortError') {
|
|
78
|
-
console.warn(`TenxGraphClient: Stop graph timeout after ${context.timeout}ms`);
|
|
79
|
-
throw new Error(`Request timeout after ${context.timeout}ms`);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
86
|
console.error('TenxGraphClient: Stop graph failed:', error);
|
|
83
87
|
throw error;
|
|
84
88
|
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { ResponseMetadata } from './metadata.js';
|
|
2
2
|
import { createErrorFromResponse } from '../errors.js';
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
buildHeaders,
|
|
5
|
+
getRequestCredentials,
|
|
6
|
+
RequestContext,
|
|
7
|
+
fetchWithTimeout,
|
|
8
|
+
} from '../request.js';
|
|
4
9
|
|
|
5
10
|
export interface StoreMemoryContext extends RequestContext {}
|
|
6
11
|
|
|
@@ -44,9 +49,6 @@ export async function storeMemory(
|
|
|
44
49
|
console.debug('TenxGraphClient: Storing memory with type', request.memory_type);
|
|
45
50
|
}
|
|
46
51
|
|
|
47
|
-
const controller = new AbortController();
|
|
48
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
49
|
-
|
|
50
52
|
const url = `${context.baseUrl}/v1/store/memories`;
|
|
51
53
|
|
|
52
54
|
// Prepare request body
|
|
@@ -59,18 +61,15 @@ export async function storeMemory(
|
|
|
59
61
|
metadata: request.metadata || {},
|
|
60
62
|
};
|
|
61
63
|
|
|
62
|
-
const response = await
|
|
64
|
+
const response = await fetchWithTimeout(context, url, {
|
|
63
65
|
method: 'POST',
|
|
64
66
|
headers: buildHeaders(context as RequestContext, {
|
|
65
67
|
'Content-Type': 'application/json',
|
|
66
68
|
}),
|
|
67
69
|
...getRequestCredentials(context as RequestContext),
|
|
68
70
|
body: JSON.stringify(body),
|
|
69
|
-
signal: controller.signal,
|
|
70
71
|
});
|
|
71
72
|
|
|
72
|
-
clearTimeout(timeoutId);
|
|
73
|
-
|
|
74
73
|
if (!response.ok) {
|
|
75
74
|
console.warn(`TenxGraphClient: Store memory failed with HTTP ${response.status}`);
|
|
76
75
|
const error = await createErrorFromResponse(
|