snow-flow 2.8.9 → 2.9.4
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/check-mcp-resources.sh +85 -0
- package/dist/config/snow-flow-config.js +1 -1
- package/dist/mcp/mcp-on-demand-proxy.d.ts +7 -0
- package/dist/mcp/mcp-on-demand-proxy.js +187 -0
- package/dist/mcp/servicenow-machine-learning-mcp.js +310 -60
- package/dist/mcp/servicenow-operations-mcp.d.ts +71 -1
- package/dist/mcp/servicenow-operations-mcp.js +44 -11
- package/dist/test-smart-limits.d.ts +13 -0
- package/dist/test-smart-limits.js +100 -0
- package/dist/utils/mcp-on-demand-manager.d.ts +69 -0
- package/dist/utils/mcp-on-demand-manager.js +309 -0
- package/dist/utils/mcp-process-manager.d.ts +58 -0
- package/dist/utils/mcp-process-manager.js +220 -0
- package/dist/utils/mcp-server-manager.js +50 -9
- package/dist/utils/mcp-singleton-lock.d.ts +4 -0
- package/dist/utils/mcp-singleton-lock.js +35 -8
- package/dist/utils/ml-data-fetcher.d.ts +66 -0
- package/dist/utils/ml-data-fetcher.js +288 -0
- package/dist/utils/servicenow-client.js +43 -17
- package/dist/utils/timeout-manager.d.ts +62 -0
- package/dist/utils/timeout-manager.js +352 -0
- package/package.json +1 -1
- package/test-ml-improvements.sh +76 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Smart ML Data Fetcher
|
|
4
|
+
* Handles intelligent data fetching for ML training with batching and field discovery
|
|
5
|
+
* Prevents token limit errors and optimizes data retrieval
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.MLDataFetcher = void 0;
|
|
9
|
+
const logger_js_1 = require("./logger.js");
|
|
10
|
+
const logger = new logger_js_1.Logger('MLDataFetcher');
|
|
11
|
+
class MLDataFetcher {
|
|
12
|
+
constructor(operationsMCP) {
|
|
13
|
+
this.operationsMCP = operationsMCP;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Smart fetch with automatic field discovery and batching
|
|
17
|
+
*/
|
|
18
|
+
async smartFetch(options) {
|
|
19
|
+
const { table, query = '', totalSamples = 1000, batchSize = 100, fields, discoverFields = true, includeContent = true } = options;
|
|
20
|
+
logger.info(`🧠 Smart ML data fetch for ${table} - Target: ${totalSamples} samples`);
|
|
21
|
+
// Step 1: Get total count
|
|
22
|
+
const countResult = await this.getRecordCount(table, query);
|
|
23
|
+
logger.info(`📊 Total available records: ${countResult}`);
|
|
24
|
+
// Step 2: Discover fields if needed
|
|
25
|
+
let fieldsToFetch = fields;
|
|
26
|
+
if (!fieldsToFetch && discoverFields) {
|
|
27
|
+
const discovery = await this.discoverFields(table, query);
|
|
28
|
+
fieldsToFetch = discovery.recommendedFields;
|
|
29
|
+
logger.info(`🔍 Discovered ${discovery.allFields.length} fields, using ${fieldsToFetch.length} for ML`);
|
|
30
|
+
}
|
|
31
|
+
// Step 3: Calculate optimal batching strategy
|
|
32
|
+
const actualTotal = Math.min(totalSamples, countResult);
|
|
33
|
+
const optimalBatchSize = this.calculateOptimalBatchSize(actualTotal, batchSize, fieldsToFetch?.length || 10);
|
|
34
|
+
const numBatches = Math.ceil(actualTotal / optimalBatchSize);
|
|
35
|
+
logger.info(`📦 Fetching ${actualTotal} records in ${numBatches} batches of ${optimalBatchSize}`);
|
|
36
|
+
// Step 4: Fetch data in batches
|
|
37
|
+
const allData = [];
|
|
38
|
+
for (let batch = 0; batch < numBatches; batch++) {
|
|
39
|
+
const offset = batch * optimalBatchSize;
|
|
40
|
+
const limit = Math.min(optimalBatchSize, actualTotal - offset);
|
|
41
|
+
logger.info(` Batch ${batch + 1}/${numBatches}: Fetching ${limit} records (offset: ${offset})`);
|
|
42
|
+
try {
|
|
43
|
+
const batchData = await this.fetchBatch(table, query, limit, offset, fieldsToFetch, includeContent);
|
|
44
|
+
allData.push(...batchData);
|
|
45
|
+
// Small delay between batches to avoid overwhelming the API
|
|
46
|
+
if (batch < numBatches - 1) {
|
|
47
|
+
await new Promise(resolve => setTimeout(resolve, 200)); // Increased from 100ms to 200ms
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error.message?.includes('exceeds maximum allowed tokens')) {
|
|
52
|
+
// Reduce batch size and retry
|
|
53
|
+
logger.warn(`⚠️ Token limit hit, reducing batch size and retrying...`);
|
|
54
|
+
const smallerBatchSize = Math.floor(optimalBatchSize / 2);
|
|
55
|
+
return this.smartFetch({
|
|
56
|
+
...options,
|
|
57
|
+
batchSize: smallerBatchSize
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
data: allData,
|
|
65
|
+
totalFetched: allData.length,
|
|
66
|
+
batchesProcessed: numBatches,
|
|
67
|
+
fields: fieldsToFetch || []
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Get total count of records matching query
|
|
72
|
+
*/
|
|
73
|
+
async getRecordCount(table, query) {
|
|
74
|
+
try {
|
|
75
|
+
const result = await this.operationsMCP.handleTool('snow_query_table', {
|
|
76
|
+
table,
|
|
77
|
+
query,
|
|
78
|
+
limit: 1,
|
|
79
|
+
include_content: false // Count only, no data
|
|
80
|
+
});
|
|
81
|
+
// Extract count from result
|
|
82
|
+
if (result?.content?.[0]?.text) {
|
|
83
|
+
const text = result.content[0].text;
|
|
84
|
+
const match = text.match(/Found (\d+) .* records/);
|
|
85
|
+
if (match) {
|
|
86
|
+
return parseInt(match[1], 10);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
logger.error('Failed to get record count:', error);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Discover available fields by sampling a few records
|
|
98
|
+
*/
|
|
99
|
+
async discoverFields(table, query) {
|
|
100
|
+
logger.info('🔍 Discovering fields from sample records...');
|
|
101
|
+
try {
|
|
102
|
+
// Fetch just 3 records with all fields to discover schema
|
|
103
|
+
const result = await this.operationsMCP.handleTool('snow_query_table', {
|
|
104
|
+
table,
|
|
105
|
+
query,
|
|
106
|
+
limit: 3,
|
|
107
|
+
include_content: true
|
|
108
|
+
// No fields specified = get all fields
|
|
109
|
+
});
|
|
110
|
+
const sampleData = this.extractDataFromResult(result);
|
|
111
|
+
if (sampleData.length === 0) {
|
|
112
|
+
logger.warn('No sample data available for field discovery');
|
|
113
|
+
return {
|
|
114
|
+
allFields: [],
|
|
115
|
+
recommendedFields: this.getDefaultFields(table),
|
|
116
|
+
sampleData: []
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
// Extract all field names from sample
|
|
120
|
+
const allFields = Object.keys(sampleData[0] || {});
|
|
121
|
+
// Recommend fields for ML (exclude system fields and large text fields)
|
|
122
|
+
const recommendedFields = this.selectMLFields(allFields, sampleData, table);
|
|
123
|
+
return {
|
|
124
|
+
allFields,
|
|
125
|
+
recommendedFields,
|
|
126
|
+
sampleData
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
logger.error('Field discovery failed:', error);
|
|
131
|
+
return {
|
|
132
|
+
allFields: [],
|
|
133
|
+
recommendedFields: this.getDefaultFields(table),
|
|
134
|
+
sampleData: []
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Fetch a single batch of data
|
|
140
|
+
*/
|
|
141
|
+
async fetchBatch(table, query, limit, offset, fields, includeContent = true) {
|
|
142
|
+
try {
|
|
143
|
+
// Build query with offset
|
|
144
|
+
const offsetQuery = query ? `${query}^ORDERBY${offset}` : `ORDERBY${offset}`;
|
|
145
|
+
const result = await this.operationsMCP.handleTool('snow_query_table', {
|
|
146
|
+
table,
|
|
147
|
+
query: offsetQuery,
|
|
148
|
+
limit,
|
|
149
|
+
fields,
|
|
150
|
+
include_content: includeContent
|
|
151
|
+
});
|
|
152
|
+
return this.extractDataFromResult(result);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.error(`Failed to fetch batch (offset: ${offset}, limit: ${limit}):`, error);
|
|
156
|
+
return [];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Extract data from MCP tool result
|
|
161
|
+
*/
|
|
162
|
+
extractDataFromResult(result) {
|
|
163
|
+
if (!result?.content?.[0]?.text) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
try {
|
|
167
|
+
const text = result.content[0].text;
|
|
168
|
+
// Try to parse as JSON first
|
|
169
|
+
if (text.includes('[') && text.includes(']')) {
|
|
170
|
+
const jsonMatch = text.match(/\[[\s\S]*\]/);
|
|
171
|
+
if (jsonMatch) {
|
|
172
|
+
return JSON.parse(jsonMatch[0]);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Try to extract from formatted output
|
|
176
|
+
const lines = text.split('\n');
|
|
177
|
+
const data = [];
|
|
178
|
+
let currentRecord = null;
|
|
179
|
+
for (const line of lines) {
|
|
180
|
+
if (line.includes('number:') || line.includes('sys_id:')) {
|
|
181
|
+
if (currentRecord) {
|
|
182
|
+
data.push(currentRecord);
|
|
183
|
+
}
|
|
184
|
+
currentRecord = {};
|
|
185
|
+
}
|
|
186
|
+
if (currentRecord && line.includes(':')) {
|
|
187
|
+
const [key, ...valueParts] = line.split(':');
|
|
188
|
+
const cleanKey = key.trim().replace(/^[-\s]+/, '');
|
|
189
|
+
const value = valueParts.join(':').trim();
|
|
190
|
+
if (cleanKey && value) {
|
|
191
|
+
currentRecord[cleanKey] = value;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
if (currentRecord && Object.keys(currentRecord).length > 0) {
|
|
196
|
+
data.push(currentRecord);
|
|
197
|
+
}
|
|
198
|
+
return data;
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
logger.error('Failed to extract data from result:', error);
|
|
202
|
+
return [];
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Calculate optimal batch size based on data characteristics
|
|
207
|
+
*/
|
|
208
|
+
calculateOptimalBatchSize(totalRecords, requestedBatchSize, numFields) {
|
|
209
|
+
// Estimate tokens per record (rough approximation)
|
|
210
|
+
const avgTokensPerField = 10; // Conservative estimate
|
|
211
|
+
const tokensPerRecord = numFields * avgTokensPerField;
|
|
212
|
+
const maxTokensPerBatch = 20000; // Leave buffer below 25000 limit
|
|
213
|
+
// Calculate max records per batch based on token limit
|
|
214
|
+
const maxRecordsPerBatch = Math.floor(maxTokensPerBatch / tokensPerRecord);
|
|
215
|
+
// Use the smaller of requested batch size and calculated max
|
|
216
|
+
const optimalSize = Math.min(requestedBatchSize, maxRecordsPerBatch);
|
|
217
|
+
// Ensure at least 10 records per batch but not more than total
|
|
218
|
+
return Math.max(10, Math.min(optimalSize, totalRecords));
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Select appropriate fields for ML training
|
|
222
|
+
*/
|
|
223
|
+
selectMLFields(allFields, sampleData, table) {
|
|
224
|
+
const excluded = new Set([
|
|
225
|
+
'sys_id', 'sys_created_on', 'sys_created_by', 'sys_updated_on', 'sys_updated_by',
|
|
226
|
+
'sys_mod_count', 'sys_tags', 'sys_package', 'sys_policy', 'sys_scope',
|
|
227
|
+
'sys_domain', 'sys_domain_path', 'sys_class_name'
|
|
228
|
+
]);
|
|
229
|
+
const mlFields = allFields.filter(field => {
|
|
230
|
+
// Exclude system fields
|
|
231
|
+
if (excluded.has(field))
|
|
232
|
+
return false;
|
|
233
|
+
// Check if field has useful data in samples
|
|
234
|
+
const hasData = sampleData.some(record => {
|
|
235
|
+
const value = record[field];
|
|
236
|
+
return value && value !== 'null' && value !== '';
|
|
237
|
+
});
|
|
238
|
+
return hasData;
|
|
239
|
+
});
|
|
240
|
+
// Always include key fields for the table type
|
|
241
|
+
const keyFields = this.getKeyFields(table);
|
|
242
|
+
const combinedFields = [...new Set([...keyFields, ...mlFields])];
|
|
243
|
+
// Limit to 20 most relevant fields to avoid token issues
|
|
244
|
+
return combinedFields.slice(0, 20);
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get default fields for a table type
|
|
248
|
+
*/
|
|
249
|
+
getDefaultFields(table) {
|
|
250
|
+
const fieldMap = {
|
|
251
|
+
incident: [
|
|
252
|
+
'number', 'short_description', 'description', 'category', 'subcategory',
|
|
253
|
+
'priority', 'urgency', 'impact', 'state', 'assignment_group',
|
|
254
|
+
'assigned_to', 'caller_id', 'opened_at', 'resolved_at'
|
|
255
|
+
],
|
|
256
|
+
change_request: [
|
|
257
|
+
'number', 'short_description', 'description', 'type', 'category',
|
|
258
|
+
'priority', 'risk', 'impact', 'state', 'assignment_group',
|
|
259
|
+
'assigned_to', 'requested_by', 'start_date', 'end_date'
|
|
260
|
+
],
|
|
261
|
+
problem: [
|
|
262
|
+
'number', 'short_description', 'description', 'category', 'subcategory',
|
|
263
|
+
'priority', 'urgency', 'impact', 'state', 'assignment_group',
|
|
264
|
+
'assigned_to', 'opened_at', 'known_error'
|
|
265
|
+
],
|
|
266
|
+
sc_request: [
|
|
267
|
+
'number', 'short_description', 'description', 'request_state', 'approval',
|
|
268
|
+
'requested_for', 'requested_by', 'assignment_group', 'assigned_to',
|
|
269
|
+
'opened_at', 'closed_at'
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
return fieldMap[table] || ['number', 'short_description', 'state', 'priority'];
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get key fields that should always be included
|
|
276
|
+
*/
|
|
277
|
+
getKeyFields(table) {
|
|
278
|
+
const keyFieldMap = {
|
|
279
|
+
incident: ['number', 'short_description', 'category', 'priority', 'state'],
|
|
280
|
+
change_request: ['number', 'short_description', 'type', 'risk', 'state'],
|
|
281
|
+
problem: ['number', 'short_description', 'category', 'priority', 'state'],
|
|
282
|
+
sc_request: ['number', 'short_description', 'request_state', 'approval']
|
|
283
|
+
};
|
|
284
|
+
return keyFieldMap[table] || ['number', 'short_description', 'state'];
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
exports.MLDataFetcher = MLDataFetcher;
|
|
288
|
+
//# sourceMappingURL=ml-data-fetcher.js.map
|
|
@@ -13,10 +13,10 @@ const axios_1 = __importDefault(require("axios"));
|
|
|
13
13
|
const https_1 = __importDefault(require("https"));
|
|
14
14
|
const snow_oauth_1 = require("./snow-oauth");
|
|
15
15
|
const action_type_cache_1 = require("./action-type-cache");
|
|
16
|
-
const snow_flow_config_js_1 = require("../config/snow-flow-config.js");
|
|
17
16
|
const widget_template_generator_js_1 = require("./widget-template-generator.js");
|
|
18
17
|
const logger_1 = require("./logger");
|
|
19
18
|
const unified_auth_store_js_1 = require("./unified-auth-store.js");
|
|
19
|
+
const timeout_manager_js_1 = require("./timeout-manager.js");
|
|
20
20
|
class ServiceNowClient {
|
|
21
21
|
constructor() {
|
|
22
22
|
this.credentials = null;
|
|
@@ -68,8 +68,10 @@ class ServiceNowClient {
|
|
|
68
68
|
maxVersion: 'TLSv1.3',
|
|
69
69
|
minVersion: 'TLSv1.2'
|
|
70
70
|
});
|
|
71
|
+
// Use intelligent timeout based on operation type (default to TABLE_QUERY)
|
|
72
|
+
const defaultTimeout = (0, timeout_manager_js_1.getTimeoutConfig)(timeout_manager_js_1.OperationType.TABLE_QUERY).baseTimeout;
|
|
71
73
|
this.client = axios_1.default.create({
|
|
72
|
-
timeout:
|
|
74
|
+
timeout: parseInt(process.env.SNOW_API_TIMEOUT || String(defaultTimeout)),
|
|
73
75
|
headers: {
|
|
74
76
|
'Content-Type': 'application/json',
|
|
75
77
|
'Accept': 'application/json'
|
|
@@ -979,21 +981,33 @@ class ServiceNowClient {
|
|
|
979
981
|
async searchRecords(table, query, limit = 10) {
|
|
980
982
|
try {
|
|
981
983
|
await this.ensureAuthenticated();
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
984
|
+
// Detect operation type for intelligent timeout
|
|
985
|
+
const operationType = (0, timeout_manager_js_1.detectOperationType)({
|
|
986
|
+
action: 'query',
|
|
987
|
+
table,
|
|
988
|
+
limit
|
|
987
989
|
});
|
|
990
|
+
// Use retry wrapper with intelligent timeout
|
|
991
|
+
const result = await (0, timeout_manager_js_1.withRetry)(async () => {
|
|
992
|
+
const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/${table}`, {
|
|
993
|
+
params: {
|
|
994
|
+
sysparm_query: query,
|
|
995
|
+
sysparm_limit: limit
|
|
996
|
+
},
|
|
997
|
+
// Override timeout for this specific request
|
|
998
|
+
timeout: (0, timeout_manager_js_1.getTimeoutConfig)(operationType).baseTimeout
|
|
999
|
+
});
|
|
1000
|
+
return response;
|
|
1001
|
+
}, operationType, `Search ${table} (${limit} records)`);
|
|
988
1002
|
return {
|
|
989
1003
|
success: true,
|
|
990
1004
|
data: {
|
|
991
|
-
result:
|
|
1005
|
+
result: result.data.result || []
|
|
992
1006
|
}
|
|
993
1007
|
};
|
|
994
1008
|
}
|
|
995
1009
|
catch (error) {
|
|
996
|
-
|
|
1010
|
+
this.logger.error(`Failed to search records in ${table}:`, error);
|
|
997
1011
|
return {
|
|
998
1012
|
success: false,
|
|
999
1013
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -1006,22 +1020,34 @@ class ServiceNowClient {
|
|
|
1006
1020
|
async searchRecordsWithOffset(table, query, limit = 10, offset = 0) {
|
|
1007
1021
|
try {
|
|
1008
1022
|
await this.ensureAuthenticated();
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
}
|
|
1023
|
+
// Detect operation type for intelligent timeout
|
|
1024
|
+
const operationType = (0, timeout_manager_js_1.detectOperationType)({
|
|
1025
|
+
action: 'query',
|
|
1026
|
+
table,
|
|
1027
|
+
limit
|
|
1015
1028
|
});
|
|
1029
|
+
// Use retry wrapper with intelligent timeout
|
|
1030
|
+
const result = await (0, timeout_manager_js_1.withRetry)(async () => {
|
|
1031
|
+
const response = await this.client.get(`${this.getBaseUrl()}/api/now/table/${table}`, {
|
|
1032
|
+
params: {
|
|
1033
|
+
sysparm_query: query,
|
|
1034
|
+
sysparm_limit: limit,
|
|
1035
|
+
sysparm_offset: offset
|
|
1036
|
+
},
|
|
1037
|
+
// Override timeout for this specific request
|
|
1038
|
+
timeout: (0, timeout_manager_js_1.getTimeoutConfig)(operationType).baseTimeout
|
|
1039
|
+
});
|
|
1040
|
+
return response;
|
|
1041
|
+
}, operationType, `Search ${table} with offset ${offset}`);
|
|
1016
1042
|
return {
|
|
1017
1043
|
success: true,
|
|
1018
1044
|
data: {
|
|
1019
|
-
result:
|
|
1045
|
+
result: result.data.result || []
|
|
1020
1046
|
}
|
|
1021
1047
|
};
|
|
1022
1048
|
}
|
|
1023
1049
|
catch (error) {
|
|
1024
|
-
|
|
1050
|
+
this.logger.error(`Failed to search records in ${table} with offset ${offset}:`, error);
|
|
1025
1051
|
return {
|
|
1026
1052
|
success: false,
|
|
1027
1053
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timeout Manager for Snow-Flow
|
|
3
|
+
* Provides intelligent timeout configuration and retry logic
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Operation types with their specific timeout requirements
|
|
7
|
+
*/
|
|
8
|
+
export declare enum OperationType {
|
|
9
|
+
SIMPLE_QUERY = "simple_query",
|
|
10
|
+
SINGLE_RECORD = "single_record",
|
|
11
|
+
HEALTH_CHECK = "health_check",
|
|
12
|
+
TABLE_QUERY = "table_query",
|
|
13
|
+
CREATE_RECORD = "create_record",
|
|
14
|
+
UPDATE_RECORD = "update_record",
|
|
15
|
+
DELETE_RECORD = "delete_record",
|
|
16
|
+
BATCH_OPERATION = "batch_operation",
|
|
17
|
+
BULK_QUERY = "bulk_query",
|
|
18
|
+
DEPLOYMENT = "deployment",
|
|
19
|
+
WORKFLOW_EXECUTION = "workflow_execution",
|
|
20
|
+
ML_TRAINING = "ml_training",
|
|
21
|
+
ML_BATCH_FETCH = "ml_batch_fetch",
|
|
22
|
+
ML_PREDICTION = "ml_prediction",
|
|
23
|
+
LARGE_EXPORT = "large_export",
|
|
24
|
+
MIGRATION = "migration",
|
|
25
|
+
FULL_SYNC = "full_sync"
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Timeout configuration with intelligent defaults
|
|
29
|
+
*/
|
|
30
|
+
export interface TimeoutConfig {
|
|
31
|
+
baseTimeout: number;
|
|
32
|
+
maxTimeout: number;
|
|
33
|
+
retryCount: number;
|
|
34
|
+
backoffMultiplier: number;
|
|
35
|
+
jitterRange: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Get timeout configuration for operation type
|
|
39
|
+
*/
|
|
40
|
+
export declare function getTimeoutConfig(operationType: OperationType): TimeoutConfig;
|
|
41
|
+
/**
|
|
42
|
+
* Calculate timeout with exponential backoff
|
|
43
|
+
*/
|
|
44
|
+
export declare function calculateTimeout(config: TimeoutConfig, attemptNumber: number): number;
|
|
45
|
+
/**
|
|
46
|
+
* Retry wrapper with exponential backoff
|
|
47
|
+
*/
|
|
48
|
+
export declare function withRetry<T>(operation: () => Promise<T>, operationType: OperationType, operationName?: string): Promise<T>;
|
|
49
|
+
/**
|
|
50
|
+
* Detect operation type from context
|
|
51
|
+
*/
|
|
52
|
+
export declare function detectOperationType(context: {
|
|
53
|
+
tool?: string;
|
|
54
|
+
table?: string;
|
|
55
|
+
action?: string;
|
|
56
|
+
limit?: number;
|
|
57
|
+
}): OperationType;
|
|
58
|
+
/**
|
|
59
|
+
* Get human-readable timeout description
|
|
60
|
+
*/
|
|
61
|
+
export declare function getTimeoutDescription(operationType: OperationType): string;
|
|
62
|
+
//# sourceMappingURL=timeout-manager.d.ts.map
|