10xgraph-client 0.0.0-stage → 0.6.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/CHANGELOG.md +276 -0
- package/LICENSE +21 -0
- package/README.md +400 -2
- package/dist/agent.d.ts +22 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/client.d.ts +479 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/compat.d.ts +28 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/endpoints/addThreadMessages.d.ts +22 -0
- package/dist/endpoints/addThreadMessages.d.ts.map +1 -0
- package/dist/endpoints/clearThreadState.d.ts +15 -0
- package/dist/endpoints/clearThreadState.d.ts.map +1 -0
- package/dist/endpoints/deleteMemory.d.ts +19 -0
- package/dist/endpoints/deleteMemory.d.ts.map +1 -0
- package/dist/endpoints/deleteThread.d.ts +19 -0
- package/dist/endpoints/deleteThread.d.ts.map +1 -0
- package/dist/endpoints/deleteThreadMessage.d.ts +20 -0
- package/dist/endpoints/deleteThreadMessage.d.ts.map +1 -0
- package/dist/endpoints/files.d.ts +83 -0
- package/dist/endpoints/files.d.ts.map +1 -0
- package/dist/endpoints/fixGraph.d.ts +29 -0
- package/dist/endpoints/fixGraph.d.ts.map +1 -0
- package/dist/endpoints/forgetMemories.d.ts +22 -0
- package/dist/endpoints/forgetMemories.d.ts.map +1 -0
- package/dist/endpoints/getMemory.d.ts +19 -0
- package/dist/endpoints/getMemory.d.ts.map +1 -0
- package/dist/endpoints/graph.d.ts +39 -0
- package/dist/endpoints/graph.d.ts.map +1 -0
- package/dist/endpoints/graphTools.d.ts +32 -0
- package/dist/endpoints/graphTools.d.ts.map +1 -0
- package/dist/endpoints/invoke.d.ts +59 -0
- package/dist/endpoints/invoke.d.ts.map +1 -0
- package/dist/endpoints/listMemories.d.ts +19 -0
- package/dist/endpoints/listMemories.d.ts.map +1 -0
- package/dist/endpoints/metadata.d.ts +6 -0
- package/dist/endpoints/metadata.d.ts.map +1 -0
- package/dist/endpoints/observability.d.ts +58 -0
- package/dist/endpoints/observability.d.ts.map +1 -0
- package/dist/endpoints/ping.d.ts +10 -0
- package/dist/endpoints/ping.d.ts.map +1 -0
- package/dist/endpoints/realtime.d.ts +134 -0
- package/dist/endpoints/realtime.d.ts.map +1 -0
- package/dist/endpoints/searchMemory.d.ts +57 -0
- package/dist/endpoints/searchMemory.d.ts.map +1 -0
- package/dist/endpoints/stateSchema.d.ts +50 -0
- package/dist/endpoints/stateSchema.d.ts.map +1 -0
- package/dist/endpoints/stopGraph.d.ts +26 -0
- package/dist/endpoints/stopGraph.d.ts.map +1 -0
- package/dist/endpoints/storeMemory.d.ts +33 -0
- package/dist/endpoints/storeMemory.d.ts.map +1 -0
- package/dist/endpoints/stream.d.ts +60 -0
- package/dist/endpoints/stream.d.ts.map +1 -0
- package/dist/endpoints/threadDetails.d.ts +19 -0
- package/dist/endpoints/threadDetails.d.ts.map +1 -0
- package/dist/endpoints/threadMessage.d.ts +17 -0
- package/dist/endpoints/threadMessage.d.ts.map +1 -0
- package/dist/endpoints/threadMessages.d.ts +23 -0
- package/dist/endpoints/threadMessages.d.ts.map +1 -0
- package/dist/endpoints/threadState.d.ts +14 -0
- package/dist/endpoints/threadState.d.ts.map +1 -0
- package/dist/endpoints/threads.d.ts +30 -0
- package/dist/endpoints/threads.d.ts.map +1 -0
- package/dist/endpoints/updateMemory.d.ts +21 -0
- package/dist/endpoints/updateMemory.d.ts.map +1 -0
- package/dist/endpoints/updateThreadState.d.ts +18 -0
- package/dist/endpoints/updateThreadState.d.ts.map +1 -0
- package/dist/endpoints/wsStream.d.ts +33 -0
- package/dist/endpoints/wsStream.d.ts.map +1 -0
- package/dist/errors.d.ts +155 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2664 -0
- package/dist/index.js.map +1 -0
- package/dist/message.d.ts +174 -0
- package/dist/message.d.ts.map +1 -0
- package/dist/request.d.ts +33 -0
- package/dist/request.d.ts.map +1 -0
- package/dist/tools.d.ts +67 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/ws.d.ts +48 -0
- package/dist/ws.d.ts.map +1 -0
- package/package.json +99 -4
- package/src/agent.ts +43 -0
- package/src/client.ts +1044 -0
- package/src/compat.ts +35 -0
- package/src/endpoints/addThreadMessages.ts +83 -0
- package/src/endpoints/clearThreadState.ts +75 -0
- package/src/endpoints/deleteMemory.ts +91 -0
- package/src/endpoints/deleteThread.ts +78 -0
- package/src/endpoints/deleteThreadMessage.ts +83 -0
- package/src/endpoints/files.ts +274 -0
- package/src/endpoints/fixGraph.ts +91 -0
- package/src/endpoints/forgetMemories.ts +95 -0
- package/src/endpoints/getMemory.ts +82 -0
- package/src/endpoints/graph.ts +97 -0
- package/src/endpoints/graphTools.ts +90 -0
- package/src/endpoints/invoke.ts +318 -0
- package/src/endpoints/listMemories.ts +97 -0
- package/src/endpoints/metadata.ts +6 -0
- package/src/endpoints/observability.ts +107 -0
- package/src/endpoints/ping.ts +58 -0
- package/src/endpoints/realtime.ts +326 -0
- package/src/endpoints/searchMemory.ts +132 -0
- package/src/endpoints/stateSchema.ts +106 -0
- package/src/endpoints/stopGraph.ts +85 -0
- package/src/endpoints/storeMemory.ts +98 -0
- package/src/endpoints/stream.ts +440 -0
- package/src/endpoints/threadDetails.ts +78 -0
- package/src/endpoints/threadMessage.ts +76 -0
- package/src/endpoints/threadMessages.ts +97 -0
- package/src/endpoints/threadState.ts +74 -0
- package/src/endpoints/threads.ts +112 -0
- package/src/endpoints/updateMemory.ts +90 -0
- package/src/endpoints/updateThreadState.ts +82 -0
- package/src/endpoints/wsStream.ts +251 -0
- package/src/errors.ts +553 -0
- package/src/index.ts +108 -0
- package/src/message.ts +436 -0
- package/src/request.ts +168 -0
- package/src/tools.ts +225 -0
- package/src/ws.ts +100 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { Message } from '../message.js';
|
|
2
|
+
import { ToolExecutor } from '../tools.js';
|
|
3
|
+
import { RequestContext } from '../request.js';
|
|
4
|
+
import { buildWsUrl, openWebSocket } from '../ws.js';
|
|
5
|
+
import { StreamChunk, StreamEventType, StreamRequest, serializeMessage } from './stream.js';
|
|
6
|
+
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// Public types
|
|
9
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
|
|
11
|
+
export interface WsStreamContext extends RequestContext {
|
|
12
|
+
toolExecutor?: ToolExecutor;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
16
|
+
// Internal types (mirror the server's WsGraphInputSchema)
|
|
17
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
18
|
+
|
|
19
|
+
interface WsGraphInput {
|
|
20
|
+
invoke_type: 'fresh' | 'resume';
|
|
21
|
+
messages?: any[];
|
|
22
|
+
tool_result?: any[];
|
|
23
|
+
initial_state?: Record<string, any>;
|
|
24
|
+
config?: Record<string, any>;
|
|
25
|
+
recursion_limit?: number;
|
|
26
|
+
response_granularity?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
30
|
+
// Helpers
|
|
31
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
/** True when any collected message contains a remote_tool_call block. */
|
|
34
|
+
function hasRemoteToolCalls(messages: Message[]): boolean {
|
|
35
|
+
return messages.some(
|
|
36
|
+
(msg) => msg.content && msg.content.some((block: any) => block.type === 'remote_tool_call')
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
41
|
+
// Core implementation
|
|
42
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Stream invoke via a persistent WebSocket connection.
|
|
46
|
+
*
|
|
47
|
+
* The protocol is:
|
|
48
|
+
*
|
|
49
|
+
* 1. Connect to ``/v1/graph/ws`` (auth via the ``10xgraph-bearer`` subprotocol or Authorization header).
|
|
50
|
+
* 2. Send ``{ invoke_type:"fresh", messages:[…], config:{…}, … }``.
|
|
51
|
+
* 3. Receive ``StreamChunk`` JSON messages; yield each to the caller.
|
|
52
|
+
* 4. Server sends ``{ event:"updates", data:{ status:"done" } }`` after each run.
|
|
53
|
+
* 5. If the run contained remote tool calls, execute them and send:
|
|
54
|
+
* ``{ invoke_type:"resume", tool_result:[…], config:{ thread_id } }``.
|
|
55
|
+
* 6. Repeat from step 3 until no more tool calls.
|
|
56
|
+
* 7. Close the WebSocket.
|
|
57
|
+
*
|
|
58
|
+
* This replaces the HTTP loop in ``streamInvoke`` — the round-trip cost of
|
|
59
|
+
* re-opening a new HTTP connection for each tool call is eliminated.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const stream = wsStreamInvoke(context, request);
|
|
64
|
+
* for await (const chunk of stream) {
|
|
65
|
+
* if (chunk.event === 'message') console.log(chunk.message);
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export async function* wsStreamInvoke(
|
|
70
|
+
context: WsStreamContext,
|
|
71
|
+
request: StreamRequest
|
|
72
|
+
): AsyncGenerator<StreamChunk, void, unknown> {
|
|
73
|
+
const url = buildWsUrl(context, '/v1/graph/ws');
|
|
74
|
+
|
|
75
|
+
if (context.debug) {
|
|
76
|
+
console.debug('TenxGraphClient [WS]: connecting to', url);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const ws = openWebSocket(url, context);
|
|
80
|
+
|
|
81
|
+
// ── Queue bridge ──────────────────────────────────────────────────────────
|
|
82
|
+
// WebSocket is event-based; async generators are pull-based.
|
|
83
|
+
// We buffer incoming items in a queue and wake up the generator each time.
|
|
84
|
+
const queue: Array<StreamChunk | Error | 'close'> = [];
|
|
85
|
+
let wakeUp: (() => void) | null = null;
|
|
86
|
+
|
|
87
|
+
const enqueue = (item: StreamChunk | Error | 'close'): void => {
|
|
88
|
+
queue.push(item);
|
|
89
|
+
if (wakeUp) {
|
|
90
|
+
const fn = wakeUp;
|
|
91
|
+
wakeUp = null;
|
|
92
|
+
fn();
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
const waitForItem = (): Promise<void> =>
|
|
97
|
+
new Promise((resolve) => {
|
|
98
|
+
if (queue.length > 0) {
|
|
99
|
+
resolve();
|
|
100
|
+
} else {
|
|
101
|
+
wakeUp = resolve;
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
ws.addEventListener('message', (event: MessageEvent) => {
|
|
106
|
+
try {
|
|
107
|
+
const chunk = JSON.parse(event.data as string) as StreamChunk;
|
|
108
|
+
enqueue(chunk);
|
|
109
|
+
} catch (e) {
|
|
110
|
+
if (context.debug) {
|
|
111
|
+
console.warn('TenxGraphClient [WS]: failed to parse chunk:', e);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
ws.addEventListener('error', () => {
|
|
117
|
+
enqueue(new Error('WebSocket error'));
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
ws.addEventListener('close', (event: CloseEvent) => {
|
|
121
|
+
if (context.debug) {
|
|
122
|
+
console.debug('TenxGraphClient [WS]: connection closed, code=', event.code);
|
|
123
|
+
}
|
|
124
|
+
enqueue('close');
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Wait for the connection to open (or fail)
|
|
128
|
+
await new Promise<void>((resolve, reject) => {
|
|
129
|
+
// Numeric readyState literals (OPEN===1) instead of WebSocket.OPEN: the
|
|
130
|
+
// global WebSocket may be absent on Node < 21 when a custom impl is injected.
|
|
131
|
+
if (ws.readyState === 1) {
|
|
132
|
+
resolve();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
ws.addEventListener('open', () => resolve(), { once: true });
|
|
136
|
+
ws.addEventListener('error', () => reject(new Error('WebSocket connection failed')), {
|
|
137
|
+
once: true,
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
if (context.debug) {
|
|
142
|
+
console.debug('TenxGraphClient [WS]: connected');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ── Main loop ─────────────────────────────────────────────────────────────
|
|
146
|
+
let threadId: string | undefined = (request.config as Record<string, any>)?.thread_id;
|
|
147
|
+
|
|
148
|
+
let nextPayload: WsGraphInput = {
|
|
149
|
+
invoke_type: 'fresh',
|
|
150
|
+
messages: request.messages,
|
|
151
|
+
initial_state: request.initial_state,
|
|
152
|
+
config: request.config,
|
|
153
|
+
recursion_limit: request.recursion_limit ?? 25,
|
|
154
|
+
response_granularity: request.response_granularity,
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
try {
|
|
158
|
+
outerLoop: while (true) {
|
|
159
|
+
if (context.debug) {
|
|
160
|
+
console.debug(
|
|
161
|
+
`TenxGraphClient [WS]: sending ${nextPayload.invoke_type} request, thread_id=${threadId ?? 'new'}`
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
ws.send(JSON.stringify(nextPayload));
|
|
166
|
+
|
|
167
|
+
// ── Inner loop: receive chunks until the server sends "done" ──────
|
|
168
|
+
const runMessages: Message[] = [];
|
|
169
|
+
|
|
170
|
+
innerLoop: while (true) {
|
|
171
|
+
await waitForItem();
|
|
172
|
+
const item = queue.shift()!;
|
|
173
|
+
|
|
174
|
+
if (item === 'close') {
|
|
175
|
+
// Server closed the connection unexpectedly
|
|
176
|
+
break outerLoop;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (item instanceof Error) {
|
|
180
|
+
throw item;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const chunk = item as StreamChunk;
|
|
184
|
+
|
|
185
|
+
// Track thread_id for resume requests
|
|
186
|
+
if (chunk.thread_id) {
|
|
187
|
+
threadId = chunk.thread_id;
|
|
188
|
+
}
|
|
189
|
+
if ((chunk.metadata as Record<string, any>)?.thread_id) {
|
|
190
|
+
threadId = (chunk.metadata as Record<string, any>).thread_id as string;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// "done" signal: current run is complete
|
|
194
|
+
if (chunk.event === StreamEventType.UPDATES && (chunk.data as any)?.status === 'done') {
|
|
195
|
+
break innerLoop;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Accumulate messages for tool-call detection
|
|
199
|
+
if (chunk.message) {
|
|
200
|
+
runMessages.push(chunk.message);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Yield every chunk to the caller (same as HTTP stream)
|
|
204
|
+
yield chunk;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (context.debug) {
|
|
208
|
+
console.debug(
|
|
209
|
+
`TenxGraphClient [WS]: run complete, ${runMessages.length} messages collected`
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// ── Tool-call detection & resume ──────────────────────────────────
|
|
214
|
+
if (hasRemoteToolCalls(runMessages) && context.toolExecutor) {
|
|
215
|
+
if (context.debug) {
|
|
216
|
+
console.debug('TenxGraphClient [WS]: remote tool calls detected, executing…');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const toolResults = await context.toolExecutor.executeToolCalls(runMessages);
|
|
220
|
+
|
|
221
|
+
if (context.debug) {
|
|
222
|
+
console.debug(
|
|
223
|
+
`TenxGraphClient [WS]: ${toolResults.length} tool result(s) ready, resuming`
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
nextPayload = {
|
|
228
|
+
invoke_type: 'resume',
|
|
229
|
+
tool_result: toolResults.map(serializeMessage),
|
|
230
|
+
config: { ...(request.config ?? {}), thread_id: threadId },
|
|
231
|
+
recursion_limit: request.recursion_limit ?? 25,
|
|
232
|
+
response_granularity: request.response_granularity,
|
|
233
|
+
};
|
|
234
|
+
// continue outerLoop → send resume request
|
|
235
|
+
} else {
|
|
236
|
+
// No tool calls — the full run is done
|
|
237
|
+
break outerLoop;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
} finally {
|
|
241
|
+
// CONNECTING===0, OPEN===1 (numeric literals; the global WebSocket may be
|
|
242
|
+
// absent on Node < 21 when a custom impl is injected).
|
|
243
|
+
if (ws.readyState === 1 || ws.readyState === 0) {
|
|
244
|
+
ws.close(1000);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (context.debug) {
|
|
248
|
+
console.debug('TenxGraphClient [WS]: stream finished');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|