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
|
@@ -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 GraphToolsContext extends RequestContext {}
|
|
6
11
|
|
|
@@ -41,21 +46,15 @@ export async function graphTools(context: GraphToolsContext): Promise<GraphTools
|
|
|
41
46
|
console.debug('TenxGraphClient: Fetching graph tools from', context.baseUrl);
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
const
|
|
45
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
46
|
-
|
|
47
|
-
const response = await fetch(`${context.baseUrl}/v1/graph/tools`, {
|
|
49
|
+
const response = await fetchWithTimeout(context, `${context.baseUrl}/v1/graph/tools`, {
|
|
48
50
|
method: 'GET',
|
|
49
51
|
headers: buildHeaders(context as RequestContext, {
|
|
50
52
|
'Content-Type': 'application/json',
|
|
51
53
|
accept: 'application/json',
|
|
52
54
|
}),
|
|
53
55
|
...getRequestCredentials(context as RequestContext),
|
|
54
|
-
signal: controller.signal,
|
|
55
56
|
});
|
|
56
57
|
|
|
57
|
-
clearTimeout(timeoutId);
|
|
58
|
-
|
|
59
58
|
if (!response.ok) {
|
|
60
59
|
console.warn(`TenxGraphClient: Graph tools fetch failed with HTTP ${response.status}`);
|
|
61
60
|
const error = await createErrorFromResponse(
|
|
@@ -79,11 +78,6 @@ export async function graphTools(context: GraphToolsContext): Promise<GraphTools
|
|
|
79
78
|
console.debug('TenxGraphClient: Graph tools fetch failed:', error);
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
if ((error as Error).name === 'AbortError') {
|
|
83
|
-
console.warn(`TenxGraphClient: Graph tools fetch timeout after ${context.timeout}ms`);
|
|
84
|
-
throw new Error(`Request timeout after ${context.timeout}ms`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
81
|
console.error('TenxGraphClient: Graph tools fetch failed:', error);
|
|
88
82
|
throw error;
|
|
89
83
|
}
|
package/src/endpoints/invoke.ts
CHANGED
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import { Message } from '../message.js';
|
|
2
2
|
import { AgentState } from '../agent.js';
|
|
3
3
|
import { ToolExecutor } from '../tools.js';
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
createErrorFromResponse,
|
|
6
|
+
NetworkError,
|
|
7
|
+
RequestTimeoutError,
|
|
8
|
+
StreamError,
|
|
9
|
+
} from '../errors.js';
|
|
10
|
+
import { serializeMessage } from './stream.js';
|
|
11
|
+
import {
|
|
12
|
+
buildHeaders,
|
|
13
|
+
getRequestCredentials,
|
|
14
|
+
linkAbortSignal,
|
|
15
|
+
RequestContext,
|
|
16
|
+
} from '../request.js';
|
|
6
17
|
|
|
7
18
|
export interface InvokeContext extends RequestContext {
|
|
8
19
|
toolExecutor?: ToolExecutor;
|
|
20
|
+
/** Caller-supplied signal; aborting it cancels the in-flight request. */
|
|
21
|
+
signal?: AbortSignal;
|
|
9
22
|
}
|
|
10
23
|
|
|
11
24
|
// Invoke Request payload
|
|
@@ -14,6 +27,12 @@ export interface InvokeRequest {
|
|
|
14
27
|
initial_state?: Record<string, any>;
|
|
15
28
|
config?: Record<string, any>;
|
|
16
29
|
recursion_limit?: number;
|
|
30
|
+
/** What to do when another run is active on the same thread (server default: 'wait'). */
|
|
31
|
+
on_busy?: 'wait' | 'cancel';
|
|
32
|
+
/** Value that answers an open interrupt. Send together with `interrupt_id`. */
|
|
33
|
+
resume?: unknown;
|
|
34
|
+
/** Id of the interrupt being answered by `resume`. */
|
|
35
|
+
interrupt_id?: string;
|
|
17
36
|
response_granularity?: 'full' | 'partial' | 'low';
|
|
18
37
|
}
|
|
19
38
|
|
|
@@ -74,45 +93,78 @@ async function makeSingleInvokeCall(
|
|
|
74
93
|
request: InvokeRequest
|
|
75
94
|
): Promise<InvokeResponse> {
|
|
76
95
|
const controller = new AbortController();
|
|
77
|
-
|
|
96
|
+
// The timeout and the caller's signal stay armed until the body is read, so a server that
|
|
97
|
+
// sends headers and then stalls is cut off too. A timeout of 0 means no timeout.
|
|
98
|
+
const timeoutId =
|
|
99
|
+
context.timeout > 0 ? setTimeout(() => controller.abort(), context.timeout) : undefined;
|
|
100
|
+
const unlink = linkAbortSignal(controller, context.signal);
|
|
78
101
|
|
|
79
102
|
try {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
103
|
+
let response: Response;
|
|
104
|
+
try {
|
|
105
|
+
response = await fetch(`${context.baseUrl}/v1/graph/invoke`, {
|
|
106
|
+
method: 'POST',
|
|
107
|
+
headers: buildHeaders(context as RequestContext, {
|
|
108
|
+
'Content-Type': 'application/json',
|
|
109
|
+
accept: 'application/json',
|
|
110
|
+
}),
|
|
111
|
+
...getRequestCredentials(context as RequestContext),
|
|
112
|
+
body: JSON.stringify(request),
|
|
113
|
+
signal: controller.signal,
|
|
114
|
+
});
|
|
115
|
+
} catch (error) {
|
|
116
|
+
if (error instanceof TypeError) {
|
|
117
|
+
throw new NetworkError(
|
|
118
|
+
`Network error: ${error.message}`,
|
|
119
|
+
'/v1/graph/invoke',
|
|
120
|
+
'POST',
|
|
121
|
+
error
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
92
126
|
|
|
93
127
|
if (!response.ok) {
|
|
94
128
|
console.warn(`TenxGraphClient: Invoke failed with HTTP ${response.status}`);
|
|
95
129
|
const error = await createErrorFromResponse(
|
|
96
130
|
response,
|
|
97
131
|
'Invoke request failed',
|
|
98
|
-
'/v1/invoke',
|
|
132
|
+
'/v1/graph/invoke',
|
|
99
133
|
'POST'
|
|
100
134
|
);
|
|
101
135
|
throw error;
|
|
102
136
|
}
|
|
103
137
|
|
|
104
138
|
const data: InvokeResponse = await response.json();
|
|
139
|
+
// A body without `data` (or without `messages`) must not crash the tool loop later.
|
|
140
|
+
if (!data || typeof data !== 'object' || !data.data || typeof data.data !== 'object') {
|
|
141
|
+
throw new StreamError(
|
|
142
|
+
'Invoke response had no data object',
|
|
143
|
+
'INVALID_RESPONSE',
|
|
144
|
+
'unknown',
|
|
145
|
+
'/v1/graph/invoke',
|
|
146
|
+
'POST'
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
if (!Array.isArray(data.data.messages)) {
|
|
150
|
+
data.data.messages = [];
|
|
151
|
+
}
|
|
105
152
|
return data;
|
|
106
153
|
} catch (error) {
|
|
107
|
-
clearTimeout(timeoutId);
|
|
108
|
-
|
|
109
154
|
if ((error as Error).name === 'AbortError') {
|
|
155
|
+
if (context.signal?.aborted) {
|
|
156
|
+
// Cancelled by the caller, not a timeout: surface the abort as is.
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
110
159
|
console.warn(`TenxGraphClient: Invoke timeout after ${context.timeout}ms`);
|
|
111
|
-
throw new
|
|
160
|
+
throw new RequestTimeoutError(context.timeout, '/v1/graph/invoke', 'POST', error);
|
|
112
161
|
}
|
|
113
162
|
|
|
114
163
|
console.error('TenxGraphClient: Invoke failed:', error);
|
|
115
164
|
throw error;
|
|
165
|
+
} finally {
|
|
166
|
+
if (timeoutId !== undefined) clearTimeout(timeoutId);
|
|
167
|
+
unlink();
|
|
116
168
|
}
|
|
117
169
|
}
|
|
118
170
|
|
|
@@ -137,7 +189,9 @@ export async function invoke(
|
|
|
137
189
|
request: InvokeRequest,
|
|
138
190
|
onPartialResult?: InvokeCallback
|
|
139
191
|
): Promise<InvokeResult> {
|
|
140
|
-
const recursion_limit = request.recursion_limit
|
|
192
|
+
const recursion_limit = request.recursion_limit ?? 25;
|
|
193
|
+
// At least one request is always sent; the limit caps tool round trips after that.
|
|
194
|
+
const maxRuns = Math.max(1, recursion_limit);
|
|
141
195
|
|
|
142
196
|
if (context.debug) {
|
|
143
197
|
console.debug('TenxGraphClient: Starting invoke with recursion_limit:', recursion_limit);
|
|
@@ -151,15 +205,20 @@ export async function invoke(
|
|
|
151
205
|
let recursionLimitReached = false;
|
|
152
206
|
let lastResponse: InvokeResponse | undefined;
|
|
153
207
|
const initial_state = request.initial_state;
|
|
154
|
-
|
|
208
|
+
// Copied so a server-assigned thread_id can be added without touching the caller's object
|
|
209
|
+
let config = request.config;
|
|
155
210
|
const response_granularity = request.response_granularity;
|
|
211
|
+
const on_busy = request.on_busy;
|
|
212
|
+
const resume = request.resume;
|
|
213
|
+
const interrupt_id = request.interrupt_id;
|
|
156
214
|
|
|
157
215
|
// Main recursion loop
|
|
158
|
-
while (
|
|
216
|
+
while (true) {
|
|
217
|
+
context.signal?.throwIfAborted();
|
|
159
218
|
iterations++;
|
|
160
219
|
|
|
161
220
|
if (context.debug) {
|
|
162
|
-
console.debug(`TenxGraphClient: Iteration ${iterations}/${
|
|
221
|
+
console.debug(`TenxGraphClient: Iteration ${iterations}/${maxRuns}`);
|
|
163
222
|
}
|
|
164
223
|
|
|
165
224
|
// Prepare request for this iteration
|
|
@@ -168,6 +227,9 @@ export async function invoke(
|
|
|
168
227
|
initial_state: iterations === 1 ? initial_state : undefined,
|
|
169
228
|
config,
|
|
170
229
|
recursion_limit,
|
|
230
|
+
on_busy,
|
|
231
|
+
resume: iterations === 1 ? resume : undefined,
|
|
232
|
+
interrupt_id: iterations === 1 ? interrupt_id : undefined,
|
|
171
233
|
response_granularity,
|
|
172
234
|
};
|
|
173
235
|
|
|
@@ -179,6 +241,13 @@ export async function invoke(
|
|
|
179
241
|
const response = await makeSingleInvokeCall(context, iterationRequest);
|
|
180
242
|
lastResponse = response;
|
|
181
243
|
|
|
244
|
+
// The server assigns a thread id when the caller omits one; reuse it so the
|
|
245
|
+
// tool round-trip stays on the same thread. A caller-supplied id is never replaced.
|
|
246
|
+
const returnedThreadId = response.data.meta?.thread_id;
|
|
247
|
+
if (returnedThreadId && !config?.thread_id) {
|
|
248
|
+
config = { ...(config ?? {}), thread_id: returnedThreadId };
|
|
249
|
+
}
|
|
250
|
+
|
|
182
251
|
if (context.debug) {
|
|
183
252
|
console.info('TenxGraphClient: Invoke successful');
|
|
184
253
|
console.debug('TenxGraphClient: Response:', JSON.stringify(response, null, 2));
|
|
@@ -192,6 +261,9 @@ export async function invoke(
|
|
|
192
261
|
// Check if there are remote tool calls to execute
|
|
193
262
|
const hasToolCalls = hasRemoteToolCalls(response);
|
|
194
263
|
|
|
264
|
+
// A tool round trip follows only while there is an executor and room under the limit
|
|
265
|
+
const willContinue = hasToolCalls && !!context.toolExecutor && iterations < maxRuns;
|
|
266
|
+
|
|
195
267
|
// Send partial result immediately if callback provided
|
|
196
268
|
if (onPartialResult) {
|
|
197
269
|
const partialResult: InvokePartialResult = {
|
|
@@ -202,12 +274,21 @@ export async function invoke(
|
|
|
202
274
|
summary: response.data.summary,
|
|
203
275
|
meta: response.data.meta,
|
|
204
276
|
has_tool_calls: hasToolCalls,
|
|
205
|
-
is_final: !
|
|
277
|
+
is_final: !willContinue,
|
|
206
278
|
};
|
|
207
279
|
|
|
208
280
|
await onPartialResult(partialResult);
|
|
209
281
|
}
|
|
210
282
|
|
|
283
|
+
if (hasToolCalls && context.toolExecutor && iterations >= maxRuns) {
|
|
284
|
+
// The limit stopped a loop that still wanted tools: the server thread is left waiting
|
|
285
|
+
recursionLimitReached = true;
|
|
286
|
+
if (context.debug) {
|
|
287
|
+
console.warn(`TenxGraphClient: Recursion limit of ${recursion_limit} reached`);
|
|
288
|
+
}
|
|
289
|
+
break;
|
|
290
|
+
}
|
|
291
|
+
|
|
211
292
|
if (hasToolCalls && context.toolExecutor) {
|
|
212
293
|
if (context.debug) {
|
|
213
294
|
console.debug('TenxGraphClient: Found remote tool calls, executing...');
|
|
@@ -237,14 +318,6 @@ export async function invoke(
|
|
|
237
318
|
}
|
|
238
319
|
}
|
|
239
320
|
|
|
240
|
-
// Check if we hit the recursion limit
|
|
241
|
-
if (iterations >= recursion_limit) {
|
|
242
|
-
recursionLimitReached = true;
|
|
243
|
-
if (context.debug) {
|
|
244
|
-
console.warn(`TenxGraphClient: Recursion limit of ${recursion_limit} reached`);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
321
|
// Construct the result
|
|
249
322
|
const result: InvokeResult = {
|
|
250
323
|
messages: lastResponse?.data.messages || [],
|
|
@@ -264,55 +337,3 @@ export async function invoke(
|
|
|
264
337
|
|
|
265
338
|
return result;
|
|
266
339
|
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Clean content blocks by removing empty arrays and undefined values
|
|
270
|
-
* Server requires array of content blocks
|
|
271
|
-
*/
|
|
272
|
-
function cleanContent(content: any[]): any[] {
|
|
273
|
-
// Always return as array of blocks (server requires this format)
|
|
274
|
-
return content.map((block) => {
|
|
275
|
-
const cleaned: any = {};
|
|
276
|
-
|
|
277
|
-
for (const [key, value] of Object.entries(block)) {
|
|
278
|
-
// Skip empty arrays
|
|
279
|
-
if (Array.isArray(value) && value.length === 0) {
|
|
280
|
-
continue;
|
|
281
|
-
}
|
|
282
|
-
// Skip undefined values
|
|
283
|
-
if (value === undefined) {
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
cleaned[key] = value;
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return cleaned;
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
/**
|
|
294
|
-
* Serialize a Message object for API transmission
|
|
295
|
-
*/
|
|
296
|
-
function serializeMessage(message: Message): any {
|
|
297
|
-
const serialized: any = {
|
|
298
|
-
role: message.role,
|
|
299
|
-
content: cleanContent(message.content),
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
// message_id: use "0" if not set (server will generate one)
|
|
303
|
-
if (message.message_id !== null && message.message_id !== undefined) {
|
|
304
|
-
serialized.message_id = String(message.message_id);
|
|
305
|
-
} else {
|
|
306
|
-
serialized.message_id = '0';
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Only include optional fields if they are explicitly set
|
|
310
|
-
if (message.tools_calls) {
|
|
311
|
-
serialized.tools_calls = message.tools_calls;
|
|
312
|
-
}
|
|
313
|
-
if (message.metadata && Object.keys(message.metadata).length > 0) {
|
|
314
|
-
serialized.metadata = message.metadata;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
return serialized;
|
|
318
|
-
}
|
|
@@ -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 { MemoryResult } from './searchMemory.js';
|
|
5
10
|
|
|
6
11
|
export interface ListMemoriesContext extends RequestContext {}
|
|
@@ -9,10 +14,16 @@ export interface ListMemoriesRequest {
|
|
|
9
14
|
config?: Record<string, any>;
|
|
10
15
|
options?: Record<string, any>;
|
|
11
16
|
limit?: number;
|
|
17
|
+
/** Memories to skip, for paging. Use `next_offset` from the previous page. Needs 10xgraph-api with paging support. */
|
|
18
|
+
offset?: number;
|
|
12
19
|
}
|
|
13
20
|
|
|
14
21
|
export interface ListMemoriesData {
|
|
15
22
|
memories: MemoryResult[];
|
|
23
|
+
/** True when more memories follow this page. Absent on servers without paging. */
|
|
24
|
+
has_more?: boolean;
|
|
25
|
+
/** Offset to request next, or null on the last page. */
|
|
26
|
+
next_offset?: number | null;
|
|
16
27
|
}
|
|
17
28
|
|
|
18
29
|
export interface ListMemoriesResponse {
|
|
@@ -31,17 +42,18 @@ export async function listMemories(
|
|
|
31
42
|
});
|
|
32
43
|
}
|
|
33
44
|
|
|
34
|
-
const controller = new AbortController();
|
|
35
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
36
|
-
|
|
37
45
|
const url = `${context.baseUrl}/v1/store/memories/list`;
|
|
38
46
|
|
|
39
47
|
// Prepare request body
|
|
40
|
-
|
|
48
|
+
// `offset` is sent only when given, so a call without it matches older servers.
|
|
49
|
+
const body: Record<string, unknown> = {
|
|
41
50
|
config: request.config || {},
|
|
42
51
|
options: request.options || {},
|
|
43
52
|
limit: request.limit || 100,
|
|
44
53
|
};
|
|
54
|
+
if (request.offset !== undefined) {
|
|
55
|
+
body.offset = request.offset;
|
|
56
|
+
}
|
|
45
57
|
|
|
46
58
|
if (context.debug) {
|
|
47
59
|
console.debug(
|
|
@@ -50,7 +62,7 @@ export async function listMemories(
|
|
|
50
62
|
);
|
|
51
63
|
}
|
|
52
64
|
|
|
53
|
-
const response = await
|
|
65
|
+
const response = await fetchWithTimeout(context, url, {
|
|
54
66
|
method: 'POST',
|
|
55
67
|
headers: buildHeaders(context as RequestContext, {
|
|
56
68
|
'Content-Type': 'application/json',
|
|
@@ -58,11 +70,8 @@ export async function listMemories(
|
|
|
58
70
|
}),
|
|
59
71
|
...getRequestCredentials(context as RequestContext),
|
|
60
72
|
body: JSON.stringify(body),
|
|
61
|
-
signal: controller.signal,
|
|
62
73
|
});
|
|
63
74
|
|
|
64
|
-
clearTimeout(timeoutId);
|
|
65
|
-
|
|
66
75
|
if (!response.ok) {
|
|
67
76
|
console.warn(`TenxGraphClient: List memories failed with HTTP ${response.status}`);
|
|
68
77
|
const error = await createErrorFromResponse(
|
|
@@ -85,10 +94,6 @@ export async function listMemories(
|
|
|
85
94
|
|
|
86
95
|
return data;
|
|
87
96
|
} catch (error) {
|
|
88
|
-
if ((error as Error).name === 'AbortError') {
|
|
89
|
-
console.warn(`TenxGraphClient: List memories timeout after ${context.timeout}ms`);
|
|
90
|
-
throw new Error(`Request timeout after ${context.timeout}ms`);
|
|
91
|
-
}
|
|
92
97
|
if (context.debug) {
|
|
93
98
|
console.debug('TenxGraphClient: List memories failed:', error);
|
|
94
99
|
}
|
|
@@ -1,9 +1,34 @@
|
|
|
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 ObservabilityContext extends RequestContext {}
|
|
6
11
|
|
|
12
|
+
/** Compact view of a complete message seen during a node visit. */
|
|
13
|
+
export interface ObsMessageSummary {
|
|
14
|
+
role: 'user' | 'assistant' | 'tool' | 'system' | string;
|
|
15
|
+
text?: string;
|
|
16
|
+
tool_calls?: Array<{ id: string; name: string }>;
|
|
17
|
+
tool_results?: Array<{ call_id: string; is_error: boolean }>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* One span in the run tree: `root` > `node` (one per visit) > `llm` and `tool`.
|
|
22
|
+
* The tree is built from `parent`. Fields marked 1.0.0 are absent on older servers.
|
|
23
|
+
* Values in `inputs` / `outputs` are clipped at 4000 characters
|
|
24
|
+
* (a clipped value is a string ending in `...[truncated N chars]`).
|
|
25
|
+
*
|
|
26
|
+
* `inputs` / `outputs` by kind:
|
|
27
|
+
* - root: `{ user_message }` / `{ assistant_message }`
|
|
28
|
+
* - node: `{ incoming_message }` (approximate) / `{ messages: ObsMessageSummary[] }`
|
|
29
|
+
* - llm: `null` (the prompt is not recorded) / `{ text?, tool_calls? }`
|
|
30
|
+
* - tool: `{ args }` / `{ result }`
|
|
31
|
+
*/
|
|
7
32
|
export interface ObsSpan {
|
|
8
33
|
id: string;
|
|
9
34
|
name: string;
|
|
@@ -14,6 +39,21 @@ export interface ObsSpan {
|
|
|
14
39
|
model?: string | null;
|
|
15
40
|
input_tokens?: number | null;
|
|
16
41
|
output_tokens?: number | null;
|
|
42
|
+
/** ok | error | running. */
|
|
43
|
+
status?: 'ok' | 'error' | 'running';
|
|
44
|
+
/** Error text when `status` is `error`. */
|
|
45
|
+
error?: string | null;
|
|
46
|
+
inputs?: Record<string, unknown> | null;
|
|
47
|
+
outputs?: Record<string, unknown> | null;
|
|
48
|
+
/** Graph step (node spans), else null. */
|
|
49
|
+
step?: number | null;
|
|
50
|
+
/** 1-based visit count of this node name (node spans), else null. */
|
|
51
|
+
visit?: number | null;
|
|
52
|
+
total_tokens?: number | null;
|
|
53
|
+
reasoning_tokens?: number | null;
|
|
54
|
+
/** Tool spans only. */
|
|
55
|
+
tool_name?: string | null;
|
|
56
|
+
tool_call_id?: string | null;
|
|
17
57
|
}
|
|
18
58
|
|
|
19
59
|
export interface ObsEvent {
|
|
@@ -43,14 +83,29 @@ export interface ObsRun {
|
|
|
43
83
|
usage: ObsTokenUsage;
|
|
44
84
|
llm_calls: number;
|
|
45
85
|
tool_calls: number;
|
|
86
|
+
/** Number of node visits (distinct node names on servers older than 1.0.0). */
|
|
46
87
|
iterations: number;
|
|
88
|
+
/** First error text seen in the run, else null. */
|
|
89
|
+
error?: string | null;
|
|
90
|
+
/** First model seen in the run, else null. */
|
|
91
|
+
model?: string | null;
|
|
92
|
+
models?: string[];
|
|
93
|
+
/** Human-readable limits of this run's trace (may be empty). */
|
|
94
|
+
notes?: string[];
|
|
47
95
|
}
|
|
48
96
|
|
|
97
|
+
/** Why `run` is null. */
|
|
98
|
+
export type ObsEmptyReason = 'disabled_in_production' | 'store_unavailable' | 'no_runs';
|
|
99
|
+
|
|
49
100
|
export interface ObservabilityData {
|
|
50
101
|
thread_id: string;
|
|
51
102
|
run_count: number;
|
|
52
103
|
run_ids: string[];
|
|
53
104
|
run: ObsRun | null;
|
|
105
|
+
/** False when the local trace store is off (for example MODE=production). */
|
|
106
|
+
enabled?: boolean;
|
|
107
|
+
/** Why `run` is null: tracing off, store missing, or no runs captured yet. */
|
|
108
|
+
reason?: ObsEmptyReason | null;
|
|
54
109
|
}
|
|
55
110
|
|
|
56
111
|
export interface ObservabilityResponse {
|
|
@@ -67,41 +122,29 @@ export async function observability(
|
|
|
67
122
|
threadId: string,
|
|
68
123
|
runId?: string
|
|
69
124
|
): Promise<ObservabilityResponse> {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
accept: 'application/json',
|
|
82
|
-
}),
|
|
83
|
-
...getRequestCredentials(context as RequestContext),
|
|
84
|
-
signal: controller.signal,
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
clearTimeout(timeoutId);
|
|
89
|
-
|
|
90
|
-
if (!response.ok) {
|
|
91
|
-
const error = await createErrorFromResponse(
|
|
92
|
-
response,
|
|
93
|
-
'Observability fetch failed',
|
|
94
|
-
`/v1/observability/${threadId}`,
|
|
95
|
-
'GET'
|
|
96
|
-
);
|
|
97
|
-
throw error;
|
|
125
|
+
const query = runId ? `?run_id=${encodeURIComponent(runId)}` : '';
|
|
126
|
+
const response = await fetchWithTimeout(
|
|
127
|
+
context,
|
|
128
|
+
`${context.baseUrl}/v1/observability/${encodeURIComponent(threadId)}${query}`,
|
|
129
|
+
{
|
|
130
|
+
method: 'GET',
|
|
131
|
+
headers: buildHeaders(context as RequestContext, {
|
|
132
|
+
'Content-Type': 'application/json',
|
|
133
|
+
accept: 'application/json',
|
|
134
|
+
}),
|
|
135
|
+
...getRequestCredentials(context as RequestContext),
|
|
98
136
|
}
|
|
137
|
+
);
|
|
99
138
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const error = await createErrorFromResponse(
|
|
141
|
+
response,
|
|
142
|
+
'Observability fetch failed',
|
|
143
|
+
`/v1/observability/${threadId}`,
|
|
144
|
+
'GET'
|
|
145
|
+
);
|
|
105
146
|
throw error;
|
|
106
147
|
}
|
|
148
|
+
|
|
149
|
+
return (await response.json()) as ObservabilityResponse;
|
|
107
150
|
}
|
package/src/endpoints/ping.ts
CHANGED
|
@@ -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 PingContext extends RequestContext {}
|
|
6
11
|
|
|
@@ -15,20 +20,14 @@ export async function ping(context: PingContext): Promise<PingResponse> {
|
|
|
15
20
|
console.debug('TenxGraphClient: Pinging server at', context.baseUrl);
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
const
|
|
19
|
-
const timeoutId = setTimeout(() => controller.abort(), context.timeout);
|
|
20
|
-
|
|
21
|
-
const response = await fetch(`${context.baseUrl}/ping`, {
|
|
23
|
+
const response = await fetchWithTimeout(context, `${context.baseUrl}/ping`, {
|
|
22
24
|
method: 'GET',
|
|
23
25
|
headers: buildHeaders(context as RequestContext, {
|
|
24
26
|
'Content-Type': 'application/json',
|
|
25
27
|
}),
|
|
26
28
|
...getRequestCredentials(context as RequestContext),
|
|
27
|
-
signal: controller.signal,
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
clearTimeout(timeoutId);
|
|
31
|
-
|
|
32
31
|
if (!response.ok) {
|
|
33
32
|
console.warn(`TenxGraphClient: Ping failed with HTTP ${response.status}`);
|
|
34
33
|
const error = await createErrorFromResponse(response, 'Ping request failed', '/ping', 'GET');
|
|
@@ -47,11 +46,6 @@ export async function ping(context: PingContext): Promise<PingResponse> {
|
|
|
47
46
|
console.debug('TenxGraphClient: Ping failed:', error);
|
|
48
47
|
}
|
|
49
48
|
|
|
50
|
-
if ((error as Error).name === 'AbortError') {
|
|
51
|
-
console.warn(`TenxGraphClient: Ping timeout after ${context.timeout}ms`);
|
|
52
|
-
throw new Error(`Request timeout after ${context.timeout}ms`);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
49
|
console.error('TenxGraphClient: Ping failed:', error);
|
|
56
50
|
throw error;
|
|
57
51
|
}
|