@robosystems/client 0.2.23 → 0.2.25
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/extensions/AgentClient.js +2 -2
- package/extensions/AgentClient.ts +2 -2
- package/extensions/GraphClient.d.ts +21 -1
- package/extensions/GraphClient.js +100 -32
- package/extensions/GraphClient.test.ts +176 -6
- package/extensions/GraphClient.ts +124 -34
- package/extensions/MaterializationClient.d.ts +13 -3
- package/extensions/MaterializationClient.js +68 -18
- package/extensions/MaterializationClient.ts +78 -18
- package/package.json +3 -3
- package/sdk/sdk.gen.d.ts +3 -3
- package/sdk/sdk.gen.js +3 -3
- package/sdk/sdk.gen.ts +3 -3
- package/sdk/types.gen.d.ts +6 -25
- package/sdk/types.gen.ts +6 -25
- package/sdk-extensions/AgentClient.js +2 -2
- package/sdk-extensions/AgentClient.ts +2 -2
- package/sdk-extensions/GraphClient.d.ts +21 -1
- package/sdk-extensions/GraphClient.js +100 -32
- package/sdk-extensions/GraphClient.test.ts +176 -6
- package/sdk-extensions/GraphClient.ts +124 -34
- package/sdk-extensions/MaterializationClient.d.ts +13 -3
- package/sdk-extensions/MaterializationClient.js +68 -18
- package/sdk-extensions/MaterializationClient.ts +78 -18
- package/sdk-extensions/README.md +19 -21
- package/sdk.gen.d.ts +3 -3
- package/sdk.gen.js +3 -3
- package/sdk.gen.ts +3 -3
- package/types.gen.d.ts +6 -25
- package/types.gen.ts +6 -25
|
@@ -2,13 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Graph Management Client
|
|
5
|
-
* Provides high-level graph management operations with automatic operation monitoring
|
|
5
|
+
* Provides high-level graph management operations with automatic operation monitoring.
|
|
6
|
+
* Supports SSE (Server-Sent Events) for real-time updates with polling fallback.
|
|
6
7
|
*/
|
|
7
8
|
|
|
8
9
|
import { createGraph, getGraphs, getOperationStatus } from '../sdk.gen'
|
|
9
10
|
import type { GraphMetadata, InitialEntityData } from '../types.gen'
|
|
10
11
|
import { OperationClient } from './OperationClient'
|
|
11
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when a graph operation fails (as reported by the server)
|
|
15
|
+
* This is distinct from connection/SSE errors
|
|
16
|
+
*/
|
|
17
|
+
export class GraphOperationError extends Error {
|
|
18
|
+
constructor(message: string) {
|
|
19
|
+
super(message)
|
|
20
|
+
this.name = 'GraphOperationError'
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
// API Response Types
|
|
13
25
|
interface GraphCreateResponse {
|
|
14
26
|
graph_id?: string
|
|
@@ -70,6 +82,7 @@ export interface CreateGraphOptions {
|
|
|
70
82
|
timeout?: number
|
|
71
83
|
pollInterval?: number
|
|
72
84
|
onProgress?: (message: string) => void
|
|
85
|
+
useSSE?: boolean
|
|
73
86
|
}
|
|
74
87
|
|
|
75
88
|
export class GraphClient {
|
|
@@ -94,6 +107,9 @@ export class GraphClient {
|
|
|
94
107
|
/**
|
|
95
108
|
* Create a graph and wait for completion
|
|
96
109
|
*
|
|
110
|
+
* Uses SSE (Server-Sent Events) for real-time progress updates with
|
|
111
|
+
* automatic fallback to polling if SSE connection fails.
|
|
112
|
+
*
|
|
97
113
|
* @param metadata - Graph metadata (name, description, etc.)
|
|
98
114
|
* @param initialEntity - Optional initial entity to create
|
|
99
115
|
* @param options - Additional options including:
|
|
@@ -102,8 +118,9 @@ export class GraphClient {
|
|
|
102
118
|
* create graph without populating entity data (useful for file-based ingestion).
|
|
103
119
|
* Defaults to true.
|
|
104
120
|
* - timeout: Maximum time to wait in milliseconds (default: 60000)
|
|
105
|
-
* - pollInterval: Time between status checks in milliseconds (default: 2000)
|
|
121
|
+
* - pollInterval: Time between status checks in milliseconds (default: 2000, for polling fallback)
|
|
106
122
|
* - onProgress: Callback for progress updates
|
|
123
|
+
* - useSSE: Whether to try SSE first (default: true). Falls back to polling on failure.
|
|
107
124
|
* @returns The graph ID when creation completes
|
|
108
125
|
*/
|
|
109
126
|
async createGraphAndWait(
|
|
@@ -111,7 +128,13 @@ export class GraphClient {
|
|
|
111
128
|
initialEntity?: InitialEntityInput,
|
|
112
129
|
options: CreateGraphOptions = {}
|
|
113
130
|
): Promise<string> {
|
|
114
|
-
const {
|
|
131
|
+
const {
|
|
132
|
+
createEntity = true,
|
|
133
|
+
timeout = 60000,
|
|
134
|
+
pollInterval = 2000,
|
|
135
|
+
onProgress,
|
|
136
|
+
useSSE = true,
|
|
137
|
+
} = options
|
|
115
138
|
|
|
116
139
|
if (!this.config.token) {
|
|
117
140
|
throw new Error('No API key provided. Set token in config.')
|
|
@@ -160,51 +183,118 @@ export class GraphClient {
|
|
|
160
183
|
}
|
|
161
184
|
|
|
162
185
|
// Otherwise, we have an operation_id to monitor
|
|
163
|
-
if (responseData?.operation_id) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (onProgress) {
|
|
167
|
-
onProgress(`Graph creation queued (operation: ${operationId})`)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Poll operation status
|
|
171
|
-
const maxAttempts = Math.floor(timeout / pollInterval)
|
|
172
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
173
|
-
await new Promise((resolve) => setTimeout(resolve, pollInterval))
|
|
186
|
+
if (!responseData?.operation_id) {
|
|
187
|
+
throw new Error('No graph_id or operation_id in response')
|
|
188
|
+
}
|
|
174
189
|
|
|
175
|
-
|
|
176
|
-
path: { operation_id: operationId },
|
|
177
|
-
})
|
|
190
|
+
const operationId = responseData.operation_id
|
|
178
191
|
|
|
179
|
-
|
|
180
|
-
|
|
192
|
+
if (onProgress) {
|
|
193
|
+
onProgress(`Graph creation queued (operation: ${operationId})`)
|
|
194
|
+
}
|
|
181
195
|
|
|
196
|
+
// Try SSE first, fall back to polling
|
|
197
|
+
if (useSSE) {
|
|
198
|
+
try {
|
|
199
|
+
return await this.waitWithSSE(operationId, timeout, onProgress)
|
|
200
|
+
} catch (error) {
|
|
201
|
+
// Only fall back to polling for SSE connection failures
|
|
202
|
+
// If it's a GraphOperationError, the operation actually failed - don't retry with polling
|
|
203
|
+
if (error instanceof GraphOperationError) {
|
|
204
|
+
throw error
|
|
205
|
+
}
|
|
206
|
+
// SSE connection failed, fall back to polling
|
|
182
207
|
if (onProgress) {
|
|
183
|
-
onProgress(
|
|
208
|
+
onProgress('SSE unavailable, using polling...')
|
|
184
209
|
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
185
212
|
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
213
|
+
// Fallback to polling
|
|
214
|
+
return await this.waitWithPolling(operationId, timeout, pollInterval, onProgress)
|
|
215
|
+
}
|
|
189
216
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
217
|
+
/**
|
|
218
|
+
* Wait for operation completion using SSE stream
|
|
219
|
+
*/
|
|
220
|
+
private async waitWithSSE(
|
|
221
|
+
operationId: string,
|
|
222
|
+
timeout: number,
|
|
223
|
+
onProgress?: (message: string) => void
|
|
224
|
+
): Promise<string> {
|
|
225
|
+
const result = await this.operationClient.monitorOperation<{ graph_id?: string }>(operationId, {
|
|
226
|
+
timeout,
|
|
227
|
+
onProgress: (progress) => {
|
|
228
|
+
if (onProgress) {
|
|
229
|
+
if (progress.progressPercent !== undefined) {
|
|
230
|
+
onProgress(`${progress.message} (${Math.round(progress.progressPercent)}%)`)
|
|
195
231
|
} else {
|
|
196
|
-
|
|
232
|
+
onProgress(progress.message)
|
|
197
233
|
}
|
|
198
|
-
} else if (status === 'failed') {
|
|
199
|
-
const error = statusData?.error || statusData?.message || 'Unknown error'
|
|
200
|
-
throw new Error(`Graph creation failed: ${error}`)
|
|
201
234
|
}
|
|
235
|
+
},
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
if (!result.success) {
|
|
239
|
+
throw new GraphOperationError(result.error || 'Graph creation failed')
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const graphId = result.result?.graph_id
|
|
243
|
+
if (!graphId) {
|
|
244
|
+
throw new GraphOperationError('Operation completed but no graph_id in result')
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (onProgress) {
|
|
248
|
+
onProgress(`Graph created: ${graphId}`)
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return graphId
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Wait for operation completion using polling
|
|
256
|
+
*/
|
|
257
|
+
private async waitWithPolling(
|
|
258
|
+
operationId: string,
|
|
259
|
+
timeout: number,
|
|
260
|
+
pollInterval: number,
|
|
261
|
+
onProgress?: (message: string) => void
|
|
262
|
+
): Promise<string> {
|
|
263
|
+
const maxAttempts = Math.floor(timeout / pollInterval)
|
|
264
|
+
|
|
265
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
266
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval))
|
|
267
|
+
|
|
268
|
+
const statusResponse = await getOperationStatus({
|
|
269
|
+
path: { operation_id: operationId },
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
const statusData = statusResponse.data as OperationStatusResponse
|
|
273
|
+
const status = statusData?.status
|
|
274
|
+
|
|
275
|
+
if (onProgress) {
|
|
276
|
+
onProgress(`Status: ${status} (attempt ${attempt + 1}/${maxAttempts})`)
|
|
202
277
|
}
|
|
203
278
|
|
|
204
|
-
|
|
279
|
+
if (status === 'completed') {
|
|
280
|
+
const result = statusData?.result
|
|
281
|
+
const graphId = result?.graph_id
|
|
282
|
+
|
|
283
|
+
if (graphId) {
|
|
284
|
+
if (onProgress) {
|
|
285
|
+
onProgress(`Graph created: ${graphId}`)
|
|
286
|
+
}
|
|
287
|
+
return graphId
|
|
288
|
+
} else {
|
|
289
|
+
throw new GraphOperationError('Operation completed but no graph_id in result')
|
|
290
|
+
}
|
|
291
|
+
} else if (status === 'failed') {
|
|
292
|
+
const error = statusData?.error || statusData?.message || 'Unknown error'
|
|
293
|
+
throw new GraphOperationError(`Graph creation failed: ${error}`)
|
|
294
|
+
}
|
|
205
295
|
}
|
|
206
296
|
|
|
207
|
-
throw new
|
|
297
|
+
throw new GraphOperationError(`Graph creation timed out after ${timeout}ms`)
|
|
208
298
|
}
|
|
209
299
|
|
|
210
300
|
/**
|
|
@@ -2,6 +2,7 @@ export interface MaterializationOptions {
|
|
|
2
2
|
ignoreErrors?: boolean;
|
|
3
3
|
rebuild?: boolean;
|
|
4
4
|
force?: boolean;
|
|
5
|
+
timeout?: number;
|
|
5
6
|
onProgress?: (message: string) => void;
|
|
6
7
|
}
|
|
7
8
|
export interface MaterializationResult {
|
|
@@ -27,6 +28,7 @@ export interface MaterializationStatus {
|
|
|
27
28
|
}
|
|
28
29
|
export declare class MaterializationClient {
|
|
29
30
|
private config;
|
|
31
|
+
private operationClient;
|
|
30
32
|
constructor(config: {
|
|
31
33
|
baseUrl: string;
|
|
32
34
|
credentials?: 'include' | 'same-origin' | 'omit';
|
|
@@ -36,11 +38,15 @@ export declare class MaterializationClient {
|
|
|
36
38
|
/**
|
|
37
39
|
* Materialize graph from DuckDB staging tables
|
|
38
40
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
41
|
+
* Submits a materialization job to Dagster and monitors progress via SSE.
|
|
42
|
+
* The operation runs asynchronously on the server but this method waits
|
|
43
|
+
* for completion and returns the final result.
|
|
42
44
|
*/
|
|
43
45
|
materialize(graphId: string, options?: MaterializationOptions): Promise<MaterializationResult>;
|
|
46
|
+
/**
|
|
47
|
+
* Convert SSE operation result to MaterializationResult
|
|
48
|
+
*/
|
|
49
|
+
private convertOperationResult;
|
|
44
50
|
/**
|
|
45
51
|
* Get current materialization status for the graph
|
|
46
52
|
*
|
|
@@ -48,4 +54,8 @@ export declare class MaterializationClient {
|
|
|
48
54
|
* when it was last materialized, and how long since last materialization.
|
|
49
55
|
*/
|
|
50
56
|
status(graphId: string): Promise<MaterializationStatus | null>;
|
|
57
|
+
/**
|
|
58
|
+
* Close any active SSE connections
|
|
59
|
+
*/
|
|
60
|
+
close(): void;
|
|
51
61
|
}
|
|
@@ -6,23 +6,25 @@ exports.MaterializationClient = void 0;
|
|
|
6
6
|
* Materialization Client for RoboSystems API
|
|
7
7
|
*
|
|
8
8
|
* Manages graph materialization from DuckDB staging tables.
|
|
9
|
-
*
|
|
9
|
+
* Submits materialization jobs to Dagster and monitors progress via SSE.
|
|
10
10
|
*/
|
|
11
11
|
const sdk_gen_1 = require("../sdk.gen");
|
|
12
|
+
const OperationClient_1 = require("./OperationClient");
|
|
12
13
|
class MaterializationClient {
|
|
13
14
|
constructor(config) {
|
|
14
15
|
this.config = config;
|
|
16
|
+
this.operationClient = new OperationClient_1.OperationClient(config);
|
|
15
17
|
}
|
|
16
18
|
/**
|
|
17
19
|
* Materialize graph from DuckDB staging tables
|
|
18
20
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
21
|
+
* Submits a materialization job to Dagster and monitors progress via SSE.
|
|
22
|
+
* The operation runs asynchronously on the server but this method waits
|
|
23
|
+
* for completion and returns the final result.
|
|
22
24
|
*/
|
|
23
25
|
async materialize(graphId, options = {}) {
|
|
24
26
|
try {
|
|
25
|
-
options.onProgress?.('
|
|
27
|
+
options.onProgress?.('Submitting materialization job...');
|
|
26
28
|
const request = {
|
|
27
29
|
ignore_errors: options.ignoreErrors ?? true,
|
|
28
30
|
rebuild: options.rebuild ?? false,
|
|
@@ -44,19 +46,24 @@ class MaterializationClient {
|
|
|
44
46
|
error: `Failed to materialize graph: ${response.error}`,
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
const queuedResponse = response.data;
|
|
50
|
+
const operationId = queuedResponse.operation_id;
|
|
51
|
+
options.onProgress?.(`Materialization queued (operation: ${operationId})`);
|
|
52
|
+
// Monitor the operation via SSE until completion
|
|
53
|
+
const opResult = await this.operationClient.monitorOperation(operationId, {
|
|
54
|
+
timeout: (options.timeout ?? 600) * 1000, // Convert to milliseconds, 10 minute default
|
|
55
|
+
onProgress: (progress) => {
|
|
56
|
+
if (options.onProgress) {
|
|
57
|
+
let msg = progress.message;
|
|
58
|
+
if (progress.progressPercent !== undefined) {
|
|
59
|
+
msg += ` (${progress.progressPercent.toFixed(0)}%)`;
|
|
60
|
+
}
|
|
61
|
+
options.onProgress(msg);
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
// Convert operation result to materialization result
|
|
66
|
+
return this.convertOperationResult(opResult, options);
|
|
60
67
|
}
|
|
61
68
|
catch (error) {
|
|
62
69
|
return {
|
|
@@ -71,6 +78,43 @@ class MaterializationClient {
|
|
|
71
78
|
};
|
|
72
79
|
}
|
|
73
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Convert SSE operation result to MaterializationResult
|
|
83
|
+
*/
|
|
84
|
+
convertOperationResult(opResult, options) {
|
|
85
|
+
if (opResult.success) {
|
|
86
|
+
// Extract details from SSE completion event result
|
|
87
|
+
const sseResult = opResult.result || {};
|
|
88
|
+
const tables = sseResult.tables_materialized || [];
|
|
89
|
+
const rows = sseResult.total_rows || 0;
|
|
90
|
+
const timeMs = sseResult.execution_time_ms || 0;
|
|
91
|
+
options.onProgress?.(`✅ Materialization complete: ${tables.length} tables, ` +
|
|
92
|
+
`${rows.toLocaleString()} rows in ${timeMs.toFixed(2)}ms`);
|
|
93
|
+
return {
|
|
94
|
+
status: 'success',
|
|
95
|
+
wasStale: sseResult.was_stale || false,
|
|
96
|
+
staleReason: sseResult.stale_reason,
|
|
97
|
+
tablesMaterialized: tables,
|
|
98
|
+
totalRows: rows,
|
|
99
|
+
executionTimeMs: timeMs,
|
|
100
|
+
message: sseResult.message || 'Graph materialized successfully',
|
|
101
|
+
success: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
// Operation failed or was cancelled
|
|
106
|
+
return {
|
|
107
|
+
status: 'failed',
|
|
108
|
+
wasStale: false,
|
|
109
|
+
tablesMaterialized: [],
|
|
110
|
+
totalRows: 0,
|
|
111
|
+
executionTimeMs: 0,
|
|
112
|
+
message: opResult.error || 'Operation failed',
|
|
113
|
+
success: false,
|
|
114
|
+
error: opResult.error,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
}
|
|
74
118
|
/**
|
|
75
119
|
* Get current materialization status for the graph
|
|
76
120
|
*
|
|
@@ -103,5 +147,11 @@ class MaterializationClient {
|
|
|
103
147
|
return null;
|
|
104
148
|
}
|
|
105
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Close any active SSE connections
|
|
152
|
+
*/
|
|
153
|
+
close() {
|
|
154
|
+
this.operationClient.closeAll();
|
|
155
|
+
}
|
|
106
156
|
}
|
|
107
157
|
exports.MaterializationClient = MaterializationClient;
|
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
* Materialization Client for RoboSystems API
|
|
5
5
|
*
|
|
6
6
|
* Manages graph materialization from DuckDB staging tables.
|
|
7
|
-
*
|
|
7
|
+
* Submits materialization jobs to Dagster and monitors progress via SSE.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { getMaterializationStatus, materializeGraph } from '../sdk.gen'
|
|
11
11
|
import type { MaterializeRequest } from '../types.gen'
|
|
12
|
+
import { OperationClient, type OperationResult } from './OperationClient'
|
|
12
13
|
|
|
13
14
|
export interface MaterializationOptions {
|
|
14
15
|
ignoreErrors?: boolean
|
|
15
16
|
rebuild?: boolean
|
|
16
17
|
force?: boolean
|
|
18
|
+
timeout?: number // Default 10 minutes
|
|
17
19
|
onProgress?: (message: string) => void
|
|
18
20
|
}
|
|
19
21
|
|
|
@@ -47,6 +49,7 @@ export class MaterializationClient {
|
|
|
47
49
|
headers?: Record<string, string>
|
|
48
50
|
token?: string
|
|
49
51
|
}
|
|
52
|
+
private operationClient: OperationClient
|
|
50
53
|
|
|
51
54
|
constructor(config: {
|
|
52
55
|
baseUrl: string
|
|
@@ -55,21 +58,22 @@ export class MaterializationClient {
|
|
|
55
58
|
token?: string
|
|
56
59
|
}) {
|
|
57
60
|
this.config = config
|
|
61
|
+
this.operationClient = new OperationClient(config)
|
|
58
62
|
}
|
|
59
63
|
|
|
60
64
|
/**
|
|
61
65
|
* Materialize graph from DuckDB staging tables
|
|
62
66
|
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
67
|
+
* Submits a materialization job to Dagster and monitors progress via SSE.
|
|
68
|
+
* The operation runs asynchronously on the server but this method waits
|
|
69
|
+
* for completion and returns the final result.
|
|
66
70
|
*/
|
|
67
71
|
async materialize(
|
|
68
72
|
graphId: string,
|
|
69
73
|
options: MaterializationOptions = {}
|
|
70
74
|
): Promise<MaterializationResult> {
|
|
71
75
|
try {
|
|
72
|
-
options.onProgress?.('
|
|
76
|
+
options.onProgress?.('Submitting materialization job...')
|
|
73
77
|
|
|
74
78
|
const request: MaterializeRequest = {
|
|
75
79
|
ignore_errors: options.ignoreErrors ?? true,
|
|
@@ -95,33 +99,82 @@ export class MaterializationClient {
|
|
|
95
99
|
}
|
|
96
100
|
}
|
|
97
101
|
|
|
98
|
-
const
|
|
102
|
+
const queuedResponse = response.data as { operation_id: string; message: string }
|
|
103
|
+
const operationId = queuedResponse.operation_id
|
|
104
|
+
|
|
105
|
+
options.onProgress?.(`Materialization queued (operation: ${operationId})`)
|
|
106
|
+
|
|
107
|
+
// Monitor the operation via SSE until completion
|
|
108
|
+
const opResult = await this.operationClient.monitorOperation(operationId, {
|
|
109
|
+
timeout: (options.timeout ?? 600) * 1000, // Convert to milliseconds, 10 minute default
|
|
110
|
+
onProgress: (progress) => {
|
|
111
|
+
if (options.onProgress) {
|
|
112
|
+
let msg = progress.message
|
|
113
|
+
if (progress.progressPercent !== undefined) {
|
|
114
|
+
msg += ` (${progress.progressPercent.toFixed(0)}%)`
|
|
115
|
+
}
|
|
116
|
+
options.onProgress(msg)
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
// Convert operation result to materialization result
|
|
122
|
+
return this.convertOperationResult(opResult, options)
|
|
123
|
+
} catch (error) {
|
|
124
|
+
return {
|
|
125
|
+
status: 'failed',
|
|
126
|
+
wasStale: false,
|
|
127
|
+
tablesMaterialized: [],
|
|
128
|
+
totalRows: 0,
|
|
129
|
+
executionTimeMs: 0,
|
|
130
|
+
message: error instanceof Error ? error.message : String(error),
|
|
131
|
+
success: false,
|
|
132
|
+
error: error instanceof Error ? error.message : String(error),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Convert SSE operation result to MaterializationResult
|
|
139
|
+
*/
|
|
140
|
+
private convertOperationResult(
|
|
141
|
+
opResult: OperationResult,
|
|
142
|
+
options: MaterializationOptions
|
|
143
|
+
): MaterializationResult {
|
|
144
|
+
if (opResult.success) {
|
|
145
|
+
// Extract details from SSE completion event result
|
|
146
|
+
const sseResult = opResult.result || {}
|
|
147
|
+
|
|
148
|
+
const tables = sseResult.tables_materialized || []
|
|
149
|
+
const rows = sseResult.total_rows || 0
|
|
150
|
+
const timeMs = sseResult.execution_time_ms || 0
|
|
99
151
|
|
|
100
152
|
options.onProgress?.(
|
|
101
|
-
`✅ Materialization complete: ${
|
|
102
|
-
`${
|
|
153
|
+
`✅ Materialization complete: ${tables.length} tables, ` +
|
|
154
|
+
`${rows.toLocaleString()} rows in ${timeMs.toFixed(2)}ms`
|
|
103
155
|
)
|
|
104
156
|
|
|
105
157
|
return {
|
|
106
|
-
status:
|
|
107
|
-
wasStale:
|
|
108
|
-
staleReason:
|
|
109
|
-
tablesMaterialized:
|
|
110
|
-
totalRows:
|
|
111
|
-
executionTimeMs:
|
|
112
|
-
message:
|
|
158
|
+
status: 'success',
|
|
159
|
+
wasStale: sseResult.was_stale || false,
|
|
160
|
+
staleReason: sseResult.stale_reason,
|
|
161
|
+
tablesMaterialized: tables,
|
|
162
|
+
totalRows: rows,
|
|
163
|
+
executionTimeMs: timeMs,
|
|
164
|
+
message: sseResult.message || 'Graph materialized successfully',
|
|
113
165
|
success: true,
|
|
114
166
|
}
|
|
115
|
-
}
|
|
167
|
+
} else {
|
|
168
|
+
// Operation failed or was cancelled
|
|
116
169
|
return {
|
|
117
170
|
status: 'failed',
|
|
118
171
|
wasStale: false,
|
|
119
172
|
tablesMaterialized: [],
|
|
120
173
|
totalRows: 0,
|
|
121
174
|
executionTimeMs: 0,
|
|
122
|
-
message: error
|
|
175
|
+
message: opResult.error || 'Operation failed',
|
|
123
176
|
success: false,
|
|
124
|
-
error:
|
|
177
|
+
error: opResult.error,
|
|
125
178
|
}
|
|
126
179
|
}
|
|
127
180
|
}
|
|
@@ -160,4 +213,11 @@ export class MaterializationClient {
|
|
|
160
213
|
return null
|
|
161
214
|
}
|
|
162
215
|
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Close any active SSE connections
|
|
219
|
+
*/
|
|
220
|
+
close(): void {
|
|
221
|
+
this.operationClient.closeAll()
|
|
222
|
+
}
|
|
163
223
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robosystems/client",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.25",
|
|
4
4
|
"description": "TypeScript client library for RoboSystems Financial Knowledge Graph API",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -70,11 +70,11 @@
|
|
|
70
70
|
"lint": "eslint .",
|
|
71
71
|
"lint:fix": "eslint . --fix",
|
|
72
72
|
"typecheck": "tsc --noEmit",
|
|
73
|
-
"validate": "npm run
|
|
73
|
+
"validate": "npm run validate:fix && npm run lint && npm run typecheck",
|
|
74
74
|
"feature:create": "./bin/create-feature",
|
|
75
75
|
"release:create": "./bin/create-release",
|
|
76
76
|
"pr:create": "./bin/create-pr",
|
|
77
|
-
"validate:fix": "npm run format && npm run lint:fix
|
|
77
|
+
"validate:fix": "npm run format && npm run lint:fix",
|
|
78
78
|
"test": "vitest run",
|
|
79
79
|
"test:watch": "vitest",
|
|
80
80
|
"test:all": "npm run validate && npm run test && npm run build",
|
package/sdk/sdk.gen.d.ts
CHANGED
|
@@ -433,7 +433,7 @@ export declare const listAgents: <ThrowOnError extends boolean = false>(options:
|
|
|
433
433
|
* **Execution Strategies (automatic):**
|
|
434
434
|
* - Fast operations (<5s): Immediate synchronous response
|
|
435
435
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
436
|
-
* - Long operations (>30s):
|
|
436
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
437
437
|
*
|
|
438
438
|
* **Response Mode Override:**
|
|
439
439
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -494,7 +494,7 @@ export declare const getAgentMetadata: <ThrowOnError extends boolean = false>(op
|
|
|
494
494
|
* **Execution Strategies (automatic):**
|
|
495
495
|
* - Fast operations (<5s): Immediate synchronous response
|
|
496
496
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
497
|
-
* - Long operations (>30s):
|
|
497
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
498
498
|
*
|
|
499
499
|
* **Response Mode Override:**
|
|
500
500
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -1708,7 +1708,7 @@ export declare const getFile: <ThrowOnError extends boolean = false>(options: Op
|
|
|
1708
1708
|
* **What Happens (status='uploaded'):**
|
|
1709
1709
|
* 1. File validated in S3
|
|
1710
1710
|
* 2. Row count calculated
|
|
1711
|
-
* 3. DuckDB staging triggered immediately (
|
|
1711
|
+
* 3. DuckDB staging triggered immediately (background task)
|
|
1712
1712
|
* 4. If ingest_to_graph=true, graph ingestion queued
|
|
1713
1713
|
* 5. File queryable in DuckDB within seconds
|
|
1714
1714
|
*
|
package/sdk/sdk.gen.js
CHANGED
|
@@ -1079,7 +1079,7 @@ exports.listAgents = listAgents;
|
|
|
1079
1079
|
* **Execution Strategies (automatic):**
|
|
1080
1080
|
* - Fast operations (<5s): Immediate synchronous response
|
|
1081
1081
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
1082
|
-
* - Long operations (>30s):
|
|
1082
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
1083
1083
|
*
|
|
1084
1084
|
* **Response Mode Override:**
|
|
1085
1085
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -1176,7 +1176,7 @@ exports.getAgentMetadata = getAgentMetadata;
|
|
|
1176
1176
|
* **Execution Strategies (automatic):**
|
|
1177
1177
|
* - Fast operations (<5s): Immediate synchronous response
|
|
1178
1178
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
1179
|
-
* - Long operations (>30s):
|
|
1179
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
1180
1180
|
*
|
|
1181
1181
|
* **Response Mode Override:**
|
|
1182
1182
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -3130,7 +3130,7 @@ exports.getFile = getFile;
|
|
|
3130
3130
|
* **What Happens (status='uploaded'):**
|
|
3131
3131
|
* 1. File validated in S3
|
|
3132
3132
|
* 2. Row count calculated
|
|
3133
|
-
* 3. DuckDB staging triggered immediately (
|
|
3133
|
+
* 3. DuckDB staging triggered immediately (background task)
|
|
3134
3134
|
* 4. If ingest_to_graph=true, graph ingestion queued
|
|
3135
3135
|
* 5. File queryable in DuckDB within seconds
|
|
3136
3136
|
*
|
package/sdk/sdk.gen.ts
CHANGED
|
@@ -1092,7 +1092,7 @@ export const listAgents = <ThrowOnError extends boolean = false>(options: Option
|
|
|
1092
1092
|
* **Execution Strategies (automatic):**
|
|
1093
1093
|
* - Fast operations (<5s): Immediate synchronous response
|
|
1094
1094
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
1095
|
-
* - Long operations (>30s):
|
|
1095
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
1096
1096
|
*
|
|
1097
1097
|
* **Response Mode Override:**
|
|
1098
1098
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -1189,7 +1189,7 @@ export const getAgentMetadata = <ThrowOnError extends boolean = false>(options:
|
|
|
1189
1189
|
* **Execution Strategies (automatic):**
|
|
1190
1190
|
* - Fast operations (<5s): Immediate synchronous response
|
|
1191
1191
|
* - Medium operations (5-30s): SSE streaming with progress updates
|
|
1192
|
-
* - Long operations (>30s):
|
|
1192
|
+
* - Long operations (>30s): Background queue with operation tracking
|
|
1193
1193
|
*
|
|
1194
1194
|
* **Response Mode Override:**
|
|
1195
1195
|
* Use query parameter `?mode=sync|async` to override automatic strategy selection.
|
|
@@ -3143,7 +3143,7 @@ export const getFile = <ThrowOnError extends boolean = false>(options: Options<G
|
|
|
3143
3143
|
* **What Happens (status='uploaded'):**
|
|
3144
3144
|
* 1. File validated in S3
|
|
3145
3145
|
* 2. Row count calculated
|
|
3146
|
-
* 3. DuckDB staging triggered immediately (
|
|
3146
|
+
* 3. DuckDB staging triggered immediately (background task)
|
|
3147
3147
|
* 4. If ingest_to_graph=true, graph ingestion queued
|
|
3148
3148
|
* 5. File queryable in DuckDB within seconds
|
|
3149
3149
|
*
|