unreal-engine-mcp-server 0.4.0 → 0.4.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.
Files changed (135) hide show
  1. package/.env.production +1 -1
  2. package/.github/copilot-instructions.md +45 -0
  3. package/.github/workflows/publish-mcp.yml +3 -2
  4. package/README.md +21 -5
  5. package/dist/index.js +124 -31
  6. package/dist/prompts/index.d.ts +10 -3
  7. package/dist/prompts/index.js +186 -7
  8. package/dist/resources/actors.d.ts +19 -1
  9. package/dist/resources/actors.js +55 -64
  10. package/dist/resources/assets.js +46 -62
  11. package/dist/resources/levels.d.ts +21 -3
  12. package/dist/resources/levels.js +29 -54
  13. package/dist/tools/actors.d.ts +3 -14
  14. package/dist/tools/actors.js +246 -302
  15. package/dist/tools/animation.d.ts +57 -102
  16. package/dist/tools/animation.js +429 -450
  17. package/dist/tools/assets.d.ts +13 -2
  18. package/dist/tools/assets.js +52 -44
  19. package/dist/tools/audio.d.ts +22 -13
  20. package/dist/tools/audio.js +467 -121
  21. package/dist/tools/blueprint.d.ts +32 -13
  22. package/dist/tools/blueprint.js +699 -448
  23. package/dist/tools/build_environment_advanced.d.ts +0 -1
  24. package/dist/tools/build_environment_advanced.js +190 -45
  25. package/dist/tools/consolidated-tool-definitions.js +78 -252
  26. package/dist/tools/consolidated-tool-handlers.js +506 -133
  27. package/dist/tools/debug.d.ts +72 -10
  28. package/dist/tools/debug.js +167 -31
  29. package/dist/tools/editor.d.ts +9 -2
  30. package/dist/tools/editor.js +30 -44
  31. package/dist/tools/foliage.d.ts +34 -15
  32. package/dist/tools/foliage.js +97 -107
  33. package/dist/tools/introspection.js +19 -21
  34. package/dist/tools/landscape.d.ts +1 -2
  35. package/dist/tools/landscape.js +311 -168
  36. package/dist/tools/level.d.ts +3 -28
  37. package/dist/tools/level.js +642 -192
  38. package/dist/tools/lighting.d.ts +14 -3
  39. package/dist/tools/lighting.js +236 -123
  40. package/dist/tools/materials.d.ts +25 -7
  41. package/dist/tools/materials.js +102 -79
  42. package/dist/tools/niagara.d.ts +10 -12
  43. package/dist/tools/niagara.js +74 -94
  44. package/dist/tools/performance.d.ts +12 -4
  45. package/dist/tools/performance.js +38 -79
  46. package/dist/tools/physics.d.ts +34 -10
  47. package/dist/tools/physics.js +364 -292
  48. package/dist/tools/rc.js +97 -23
  49. package/dist/tools/sequence.d.ts +1 -0
  50. package/dist/tools/sequence.js +125 -22
  51. package/dist/tools/ui.d.ts +31 -4
  52. package/dist/tools/ui.js +83 -66
  53. package/dist/tools/visual.d.ts +11 -0
  54. package/dist/tools/visual.js +245 -30
  55. package/dist/types/tool-types.d.ts +0 -6
  56. package/dist/types/tool-types.js +1 -8
  57. package/dist/unreal-bridge.d.ts +32 -2
  58. package/dist/unreal-bridge.js +621 -127
  59. package/dist/utils/elicitation.d.ts +57 -0
  60. package/dist/utils/elicitation.js +104 -0
  61. package/dist/utils/error-handler.d.ts +0 -33
  62. package/dist/utils/error-handler.js +4 -111
  63. package/dist/utils/http.d.ts +2 -22
  64. package/dist/utils/http.js +12 -75
  65. package/dist/utils/normalize.d.ts +4 -4
  66. package/dist/utils/normalize.js +15 -7
  67. package/dist/utils/python-output.d.ts +18 -0
  68. package/dist/utils/python-output.js +290 -0
  69. package/dist/utils/python.d.ts +2 -0
  70. package/dist/utils/python.js +4 -0
  71. package/dist/utils/response-validator.js +28 -2
  72. package/dist/utils/result-helpers.d.ts +27 -0
  73. package/dist/utils/result-helpers.js +147 -0
  74. package/dist/utils/safe-json.d.ts +0 -2
  75. package/dist/utils/safe-json.js +0 -43
  76. package/dist/utils/validation.d.ts +16 -0
  77. package/dist/utils/validation.js +70 -7
  78. package/mcp-config-example.json +2 -2
  79. package/package.json +10 -9
  80. package/server.json +37 -14
  81. package/src/index.ts +130 -33
  82. package/src/prompts/index.ts +211 -13
  83. package/src/resources/actors.ts +59 -44
  84. package/src/resources/assets.ts +48 -51
  85. package/src/resources/levels.ts +35 -45
  86. package/src/tools/actors.ts +269 -313
  87. package/src/tools/animation.ts +556 -539
  88. package/src/tools/assets.ts +53 -43
  89. package/src/tools/audio.ts +507 -113
  90. package/src/tools/blueprint.ts +778 -462
  91. package/src/tools/build_environment_advanced.ts +266 -64
  92. package/src/tools/consolidated-tool-definitions.ts +90 -264
  93. package/src/tools/consolidated-tool-handlers.ts +630 -121
  94. package/src/tools/debug.ts +176 -33
  95. package/src/tools/editor.ts +35 -37
  96. package/src/tools/foliage.ts +110 -104
  97. package/src/tools/introspection.ts +24 -22
  98. package/src/tools/landscape.ts +334 -181
  99. package/src/tools/level.ts +683 -182
  100. package/src/tools/lighting.ts +244 -123
  101. package/src/tools/materials.ts +114 -83
  102. package/src/tools/niagara.ts +87 -81
  103. package/src/tools/performance.ts +49 -88
  104. package/src/tools/physics.ts +393 -299
  105. package/src/tools/rc.ts +102 -24
  106. package/src/tools/sequence.ts +136 -28
  107. package/src/tools/ui.ts +101 -70
  108. package/src/tools/visual.ts +250 -29
  109. package/src/types/tool-types.ts +0 -9
  110. package/src/unreal-bridge.ts +658 -140
  111. package/src/utils/elicitation.ts +129 -0
  112. package/src/utils/error-handler.ts +4 -159
  113. package/src/utils/http.ts +16 -115
  114. package/src/utils/normalize.ts +20 -10
  115. package/src/utils/python-output.ts +351 -0
  116. package/src/utils/python.ts +3 -0
  117. package/src/utils/response-validator.ts +25 -2
  118. package/src/utils/result-helpers.ts +193 -0
  119. package/src/utils/safe-json.ts +0 -50
  120. package/src/utils/validation.ts +94 -7
  121. package/tests/run-unreal-tool-tests.mjs +720 -0
  122. package/tsconfig.json +2 -2
  123. package/dist/python-utils.d.ts +0 -29
  124. package/dist/python-utils.js +0 -54
  125. package/dist/types/index.d.ts +0 -323
  126. package/dist/types/index.js +0 -28
  127. package/dist/utils/cache-manager.d.ts +0 -64
  128. package/dist/utils/cache-manager.js +0 -176
  129. package/dist/utils/errors.d.ts +0 -133
  130. package/dist/utils/errors.js +0 -256
  131. package/src/python/editor_compat.py +0 -181
  132. package/src/python-utils.ts +0 -57
  133. package/src/types/index.ts +0 -414
  134. package/src/utils/cache-manager.ts +0 -213
  135. package/src/utils/errors.ts +0 -312
@@ -0,0 +1,57 @@
1
+ import type { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { Logger } from './logger.js';
3
+ export type PrimitiveSchema = {
4
+ type: 'string';
5
+ title?: string;
6
+ description?: string;
7
+ minLength?: number;
8
+ maxLength?: number;
9
+ pattern?: string;
10
+ format?: 'email' | 'uri' | 'date' | 'date-time';
11
+ default?: string;
12
+ } | {
13
+ type: 'number' | 'integer';
14
+ title?: string;
15
+ description?: string;
16
+ minimum?: number;
17
+ maximum?: number;
18
+ default?: number;
19
+ } | {
20
+ type: 'boolean';
21
+ title?: string;
22
+ description?: string;
23
+ default?: boolean;
24
+ } | {
25
+ type: 'string';
26
+ enum: string[];
27
+ enumNames?: string[];
28
+ title?: string;
29
+ description?: string;
30
+ default?: string;
31
+ };
32
+ export interface ElicitSchema {
33
+ type: 'object';
34
+ properties: Record<string, PrimitiveSchema>;
35
+ required?: string[];
36
+ }
37
+ export interface ElicitOptions {
38
+ timeoutMs?: number;
39
+ fallback?: () => Promise<{
40
+ ok: boolean;
41
+ value?: any;
42
+ error?: string;
43
+ }>;
44
+ }
45
+ export declare function createElicitationHelper(server: Server, log: Logger): {
46
+ supports: () => boolean;
47
+ elicit: (message: string, requestedSchema: ElicitSchema, opts?: ElicitOptions) => Promise<{
48
+ ok: boolean;
49
+ value?: any;
50
+ error?: string;
51
+ } | {
52
+ ok: boolean;
53
+ error: any;
54
+ }>;
55
+ getDefaultTimeoutMs: () => number;
56
+ };
57
+ //# sourceMappingURL=elicitation.d.ts.map
@@ -0,0 +1,104 @@
1
+ export function createElicitationHelper(server, log) {
2
+ // We do not require explicit capability detection: we optimistically try once
3
+ // and disable on a Method-not-found (-32601) error for the session.
4
+ let supported = true; // optimistic; will be set false on first failure
5
+ const MIN_TIMEOUT_MS = 30_000;
6
+ const MAX_TIMEOUT_MS = 10 * 60 * 1000;
7
+ const DEFAULT_TIMEOUT_MS = 3 * 60 * 1000;
8
+ const timeoutEnvRaw = process.env.MCP_ELICITATION_TIMEOUT_MS ?? process.env.ELICITATION_TIMEOUT_MS ?? '';
9
+ const parsedEnvTimeout = Number.parseInt(timeoutEnvRaw, 10);
10
+ const defaultTimeoutMs = Number.isFinite(parsedEnvTimeout) && parsedEnvTimeout > 0
11
+ ? Math.min(Math.max(parsedEnvTimeout, MIN_TIMEOUT_MS), MAX_TIMEOUT_MS)
12
+ : DEFAULT_TIMEOUT_MS;
13
+ if (timeoutEnvRaw) {
14
+ log.debug('Configured elicitation timeout override detected', {
15
+ defaultTimeoutMs,
16
+ fromEnv: timeoutEnvRaw
17
+ });
18
+ }
19
+ function isSafeSchema(schema) {
20
+ if (!schema || schema.type !== 'object' || typeof schema.properties !== 'object')
21
+ return false;
22
+ const propertyEntries = Object.entries(schema.properties ?? {});
23
+ const propertyKeys = propertyEntries.map(([key]) => key);
24
+ if (schema.required) {
25
+ if (!Array.isArray(schema.required))
26
+ return false;
27
+ const invalidRequired = schema.required.some((key) => typeof key !== 'string' || !propertyKeys.includes(key));
28
+ if (invalidRequired)
29
+ return false;
30
+ }
31
+ return propertyEntries.every(([, rawSchema]) => {
32
+ if (!rawSchema || typeof rawSchema !== 'object')
33
+ return false;
34
+ const primitive = rawSchema; // narrow for guards
35
+ if ('properties' in primitive || 'items' in primitive)
36
+ return false; // nested schemas unsupported
37
+ if (Array.isArray(primitive.enum)) {
38
+ const enumValues = primitive.enum;
39
+ const allStrings = enumValues.every((value) => typeof value === 'string');
40
+ if (!allStrings)
41
+ return false;
42
+ return !('type' in primitive) || primitive.type === 'string';
43
+ }
44
+ if (primitive.type === 'string')
45
+ return true;
46
+ if (primitive.type === 'number' || primitive.type === 'integer')
47
+ return true;
48
+ if (primitive.type === 'boolean')
49
+ return true;
50
+ return false;
51
+ });
52
+ }
53
+ async function elicit(message, requestedSchema, opts = {}) {
54
+ if (!supported || !isSafeSchema(requestedSchema)) {
55
+ if (opts.fallback)
56
+ return opts.fallback();
57
+ return { ok: false, error: 'elicitation-unsupported' };
58
+ }
59
+ const params = { message, requestedSchema };
60
+ try {
61
+ const elicitMethod = server?.elicitInput;
62
+ if (typeof elicitMethod !== 'function') {
63
+ supported = false;
64
+ throw new Error('elicitInput-not-available');
65
+ }
66
+ const requestedTimeout = opts.timeoutMs;
67
+ const timeoutMs = Math.max(MIN_TIMEOUT_MS, requestedTimeout ?? defaultTimeoutMs);
68
+ const res = await elicitMethod.call(server, params, { timeout: timeoutMs });
69
+ const action = res?.action;
70
+ const content = res?.content;
71
+ if (action === 'accept')
72
+ return { ok: true, value: content };
73
+ if (action === 'decline' || action === 'cancel') {
74
+ if (opts.fallback)
75
+ return opts.fallback();
76
+ return { ok: false, error: action };
77
+ }
78
+ if (opts.fallback)
79
+ return opts.fallback();
80
+ return { ok: false, error: 'unexpected-response' };
81
+ }
82
+ catch (e) {
83
+ const msg = String(e?.message || e);
84
+ const code = e?.code ?? e?.error?.code;
85
+ // If client doesn't support it, don’t try again this session
86
+ if (msg.includes('Method not found') ||
87
+ msg.includes('elicitInput-not-available') ||
88
+ msg.includes('request-not-available') ||
89
+ String(code) === '-32601') {
90
+ supported = false;
91
+ }
92
+ log.debug('Elicitation failed; falling back', { error: msg, code });
93
+ if (opts.fallback)
94
+ return opts.fallback();
95
+ return { ok: false, error: msg.includes('timeout') ? 'timeout' : 'rpc-failed' };
96
+ }
97
+ }
98
+ return {
99
+ supports: () => supported,
100
+ elicit,
101
+ getDefaultTimeoutMs: () => defaultTimeoutMs
102
+ };
103
+ }
104
+ //# sourceMappingURL=elicitation.js.map
@@ -11,15 +11,6 @@ export declare enum ErrorType {
11
11
  TIMEOUT = "TIMEOUT",
12
12
  UNKNOWN = "UNKNOWN"
13
13
  }
14
- /**
15
- * Custom error class for MCP tools
16
- */
17
- export declare class ToolError extends Error {
18
- type: ErrorType;
19
- toolName: string;
20
- originalError?: any | undefined;
21
- constructor(type: ErrorType, toolName: string, message: string, originalError?: any | undefined);
22
- }
23
14
  /**
24
15
  * Consistent error handling for all tools
25
16
  */
@@ -28,14 +19,6 @@ export declare class ErrorHandler {
28
19
  * Create a standardized error response
29
20
  */
30
21
  static createErrorResponse(error: any, toolName: string, context?: any): BaseToolResponse;
31
- /**
32
- * Create a standardized warning response
33
- */
34
- static createWarningResponse(message: string, result: any, toolName: string): BaseToolResponse;
35
- /**
36
- * Create a standardized success response
37
- */
38
- static createSuccessResponse(message: string, data?: any): BaseToolResponse;
39
22
  /**
40
23
  * Categorize error by type
41
24
  */
@@ -46,21 +29,5 @@ export declare class ErrorHandler {
46
29
  private static getUserFriendlyMessage;
47
30
  /** Determine if an error is likely retriable */
48
31
  private static isRetriable;
49
- /**
50
- * Wrap async function with error handling
51
- */
52
- static wrapAsync<T extends BaseToolResponse>(toolName: string, fn: () => Promise<T>, context?: any): Promise<T>;
53
- /**
54
- * Validate required parameters
55
- */
56
- static validateParams(params: any, required: string[], toolName: string): void;
57
- /**
58
- * Handle Unreal Engine specific errors
59
- */
60
- static handleUnrealError(error: any, operation: string): string;
61
- /**
62
- * Create operation result with consistent structure
63
- */
64
- static createResult<T extends BaseToolResponse>(success: boolean, message: string, data?: Partial<T>): T;
65
32
  }
66
33
  //# sourceMappingURL=error-handler.d.ts.map
@@ -13,21 +13,6 @@ export var ErrorType;
13
13
  ErrorType["TIMEOUT"] = "TIMEOUT";
14
14
  ErrorType["UNKNOWN"] = "UNKNOWN";
15
15
  })(ErrorType || (ErrorType = {}));
16
- /**
17
- * Custom error class for MCP tools
18
- */
19
- export class ToolError extends Error {
20
- type;
21
- toolName;
22
- originalError;
23
- constructor(type, toolName, message, originalError) {
24
- super(message);
25
- this.type = type;
26
- this.toolName = toolName;
27
- this.originalError = originalError;
28
- this.name = 'ToolError';
29
- }
30
- }
31
16
  /**
32
17
  * Consistent error handling for all tools
33
18
  */
@@ -66,36 +51,15 @@ export class ErrorHandler {
66
51
  })
67
52
  };
68
53
  }
69
- /**
70
- * Create a standardized warning response
71
- */
72
- static createWarningResponse(message, result, toolName) {
73
- log.warn(`Tool ${toolName} warning: ${message}`);
74
- return {
75
- success: true,
76
- warning: message,
77
- message: `${toolName} completed with warnings`,
78
- ...result
79
- };
80
- }
81
- /**
82
- * Create a standardized success response
83
- */
84
- static createSuccessResponse(message, data = {}) {
85
- return {
86
- success: true,
87
- message,
88
- ...data
89
- };
90
- }
91
54
  /**
92
55
  * Categorize error by type
93
56
  */
94
57
  static categorizeError(error) {
95
- if (error instanceof ToolError) {
96
- return error.type;
58
+ const explicitType = (error?.type || error?.errorType || '').toString().toUpperCase();
59
+ if (explicitType && Object.values(ErrorType).includes(explicitType)) {
60
+ return explicitType;
97
61
  }
98
- const errorMessage = error.message?.toLowerCase() || String(error).toLowerCase();
62
+ const errorMessage = error?.message?.toLowerCase() || String(error).toLowerCase();
99
63
  // Connection errors
100
64
  if (errorMessage.includes('econnrefused') ||
101
65
  errorMessage.includes('timeout') ||
@@ -168,76 +132,5 @@ export class ErrorHandler {
168
132
  catch { }
169
133
  return false;
170
134
  }
171
- /**
172
- * Wrap async function with error handling
173
- */
174
- static async wrapAsync(toolName, fn, context) {
175
- try {
176
- const result = await fn();
177
- // Ensure result has success field
178
- if (typeof result === 'object' && result !== null) {
179
- if (!('success' in result)) {
180
- result.success = true;
181
- }
182
- }
183
- return result;
184
- }
185
- catch (error) {
186
- return this.createErrorResponse(error, toolName, context);
187
- }
188
- }
189
- /**
190
- * Validate required parameters
191
- */
192
- static validateParams(params, required, toolName) {
193
- if (!params || typeof params !== 'object') {
194
- throw new ToolError(ErrorType.PARAMETER, toolName, 'Invalid parameters: expected object');
195
- }
196
- for (const field of required) {
197
- if (!(field in params) || params[field] === undefined || params[field] === null) {
198
- throw new ToolError(ErrorType.PARAMETER, toolName, `Missing required parameter: ${field}`);
199
- }
200
- // Additional validation for common types
201
- if (field.includes('Path') || field.includes('Name')) {
202
- if (typeof params[field] !== 'string' || params[field].trim() === '') {
203
- throw new ToolError(ErrorType.PARAMETER, toolName, `Invalid ${field}: must be a non-empty string`);
204
- }
205
- }
206
- }
207
- }
208
- /**
209
- * Handle Unreal Engine specific errors
210
- */
211
- static handleUnrealError(error, operation) {
212
- const errorStr = String(error.message || error).toLowerCase();
213
- // Common Unreal errors
214
- if (errorStr.includes('worldcontext')) {
215
- return `${operation} completed (WorldContext warnings are normal)`;
216
- }
217
- if (errorStr.includes('does not exist')) {
218
- return `Asset or object not found for ${operation}`;
219
- }
220
- if (errorStr.includes('access denied') || errorStr.includes('read-only')) {
221
- return `Permission denied for ${operation}. Check file permissions.`;
222
- }
223
- if (errorStr.includes('already exists')) {
224
- return `Object already exists for ${operation}`;
225
- }
226
- return `Unreal Engine error during ${operation}: ${error.message || error}`;
227
- }
228
- /**
229
- * Create operation result with consistent structure
230
- */
231
- static createResult(success, message, data) {
232
- const result = {
233
- success,
234
- message,
235
- ...(data || {})
236
- };
237
- if (!success && !result.error) {
238
- result.error = message;
239
- }
240
- return result;
241
- }
242
135
  }
243
136
  //# sourceMappingURL=error-handler.js.map
@@ -1,26 +1,6 @@
1
- import { AxiosInstance, AxiosRequestConfig } from 'axios';
2
- interface RetryConfig {
3
- maxRetries: number;
4
- initialDelay: number;
5
- maxDelay: number;
6
- backoffMultiplier: number;
7
- retryableStatuses: number[];
8
- retryableErrors: string[];
9
- }
1
+ import { AxiosInstance } from 'axios';
10
2
  /**
11
- * Enhanced HTTP client factory with connection pooling and retry logic
3
+ * Enhanced HTTP client factory with connection pooling and request timing
12
4
  */
13
5
  export declare function createHttpClient(baseURL: string): AxiosInstance;
14
- /**
15
- * Execute request with retry logic for resilience
16
- */
17
- export declare function requestWithRetry<T = any>(client: AxiosInstance, config: AxiosRequestConfig, retryConfig?: Partial<RetryConfig>): Promise<T>;
18
- /**
19
- * Batch multiple requests for efficiency
20
- */
21
- export declare function batchRequests<T = any>(client: AxiosInstance, requests: AxiosRequestConfig[], options?: {
22
- concurrency?: number;
23
- throwOnError?: boolean;
24
- }): Promise<(T | Error)[]>;
25
- export {};
26
6
  //# sourceMappingURL=http.d.ts.map
@@ -2,40 +2,24 @@ import axios from 'axios';
2
2
  import http from 'http';
3
3
  import https from 'https';
4
4
  import { Logger } from './logger.js';
5
- // Connection pooling configuration for better performance
5
+ // Enhanced connection pooling configuration to prevent socket failures
6
6
  const httpAgent = new http.Agent({
7
7
  keepAlive: true,
8
- keepAliveMsecs: 30000,
9
- maxSockets: 10,
10
- maxFreeSockets: 5,
11
- timeout: 30000
8
+ keepAliveMsecs: 60000, // Increased keep-alive time
9
+ maxSockets: 20, // Increased socket pool
10
+ maxFreeSockets: 10, // More free sockets
11
+ timeout: 60000, // Longer timeout
12
12
  });
13
13
  const httpsAgent = new https.Agent({
14
14
  keepAlive: true,
15
- keepAliveMsecs: 30000,
16
- maxSockets: 10,
17
- maxFreeSockets: 5,
18
- timeout: 30000
15
+ keepAliveMsecs: 60000, // Increased keep-alive time
16
+ maxSockets: 20, // Increased socket pool
17
+ maxFreeSockets: 10, // More free sockets
18
+ timeout: 60000, // Longer timeout
19
19
  });
20
20
  const log = new Logger('HTTP');
21
- const defaultRetryConfig = {
22
- maxRetries: 3,
23
- initialDelay: 1000,
24
- maxDelay: 10000,
25
- backoffMultiplier: 2,
26
- retryableStatuses: [408, 429, 500, 502, 503, 504],
27
- retryableErrors: ['ECONNABORTED', 'ETIMEDOUT', 'ECONNRESET', 'ENOTFOUND']
28
- };
29
21
  /**
30
- * Calculate exponential backoff delay with jitter
31
- */
32
- function calculateBackoff(attempt, config) {
33
- const delay = Math.min(config.initialDelay * Math.pow(config.backoffMultiplier, attempt - 1), config.maxDelay);
34
- // Add jitter to prevent thundering herd
35
- return delay + Math.random() * 1000;
36
- }
37
- /**
38
- * Enhanced HTTP client factory with connection pooling and retry logic
22
+ * Enhanced HTTP client factory with connection pooling and request timing
39
23
  */
40
24
  export function createHttpClient(baseURL) {
41
25
  const client = axios.create({
@@ -85,53 +69,6 @@ export function createHttpClient(baseURL) {
85
69
  });
86
70
  return client;
87
71
  }
88
- /**
89
- * Execute request with retry logic for resilience
90
- */
91
- export async function requestWithRetry(client, config, retryConfig = {}) {
92
- const retry = { ...defaultRetryConfig, ...retryConfig };
93
- let lastError = null;
94
- for (let attempt = 1; attempt <= retry.maxRetries; attempt++) {
95
- try {
96
- const response = await client.request(config);
97
- // Check if we should retry based on status
98
- if (retry.retryableStatuses.includes(response.status)) {
99
- throw new Error(`Retryable status: ${response.status}`);
100
- }
101
- return response.data;
102
- }
103
- catch (error) {
104
- lastError = error;
105
- const axiosError = error;
106
- // Check if error is retryable
107
- const isRetryable = retry.retryableErrors.includes(axiosError.code || '') ||
108
- (axiosError.response && retry.retryableStatuses.includes(axiosError.response.status));
109
- if (!isRetryable || attempt === retry.maxRetries) {
110
- throw error;
111
- }
112
- // Calculate delay and wait
113
- const delay = calculateBackoff(attempt, retry);
114
- log.debug(`[HTTP] Retry attempt ${attempt}/${retry.maxRetries} after ${Math.round(delay)}ms`);
115
- await new Promise(resolve => setTimeout(resolve, delay));
116
- }
117
- }
118
- throw lastError || new Error('Request failed after retries');
119
- }
120
- /**
121
- * Batch multiple requests for efficiency
122
- */
123
- export async function batchRequests(client, requests, options = {}) {
124
- const { concurrency = 5, throwOnError = false } = options;
125
- const results = [];
126
- // Process requests in batches
127
- for (let i = 0; i < requests.length; i += concurrency) {
128
- const batch = requests.slice(i, i + concurrency);
129
- const batchPromises = batch.map(req => client.request(req)
130
- .then(res => res.data)
131
- .catch(err => throwOnError ? Promise.reject(err) : err));
132
- const batchResults = await Promise.all(batchPromises);
133
- results.push(...batchResults);
134
- }
135
- return results;
136
- }
72
+ // No retry helpers are exported; consolidated command flows rely on
73
+ // Unreal's own retry/backoff semantics to avoid duplicate side effects.
137
74
  //# sourceMappingURL=http.js.map
@@ -1,5 +1,3 @@
1
- export type Vec3Array = [number, number, number];
2
- export type Rot3Array = [number, number, number];
3
1
  export interface Vec3Obj {
4
2
  x: number;
5
3
  y: number;
@@ -10,8 +8,10 @@ export interface Rot3Obj {
10
8
  yaw: number;
11
9
  roll: number;
12
10
  }
11
+ export type Vec3Tuple = [number, number, number];
12
+ export type Rot3Tuple = [number, number, number];
13
13
  export declare function toVec3Object(input: any): Vec3Obj | null;
14
- export declare function toVec3Array(input: any): Vec3Array | null;
15
14
  export declare function toRotObject(input: any): Rot3Obj | null;
16
- export declare function toRotArray(input: any): Rot3Array | null;
15
+ export declare function toVec3Tuple(input: any): Vec3Tuple | null;
16
+ export declare function toRotTuple(input: any): Rot3Tuple | null;
17
17
  //# sourceMappingURL=normalize.d.ts.map
@@ -18,10 +18,6 @@ export function toVec3Object(input) {
18
18
  catch { }
19
19
  return null;
20
20
  }
21
- export function toVec3Array(input) {
22
- const obj = toVec3Object(input);
23
- return obj ? [obj.x, obj.y, obj.z] : null;
24
- }
25
21
  export function toRotObject(input) {
26
22
  try {
27
23
  if (Array.isArray(input) && input.length === 3) {
@@ -42,8 +38,20 @@ export function toRotObject(input) {
42
38
  catch { }
43
39
  return null;
44
40
  }
45
- export function toRotArray(input) {
46
- const obj = toRotObject(input);
47
- return obj ? [obj.pitch, obj.yaw, obj.roll] : null;
41
+ export function toVec3Tuple(input) {
42
+ const vec = toVec3Object(input);
43
+ if (!vec) {
44
+ return null;
45
+ }
46
+ const { x, y, z } = vec;
47
+ return [x, y, z];
48
+ }
49
+ export function toRotTuple(input) {
50
+ const rot = toRotObject(input);
51
+ if (!rot) {
52
+ return null;
53
+ }
54
+ const { pitch, yaw, roll } = rot;
55
+ return [pitch, yaw, roll];
48
56
  }
49
57
  //# sourceMappingURL=normalize.js.map
@@ -0,0 +1,18 @@
1
+ export interface PythonOutput {
2
+ raw: unknown;
3
+ text: string;
4
+ }
5
+ export interface TaggedJsonResult<T> extends PythonOutput {
6
+ data: T | null;
7
+ }
8
+ export interface StandardResultPayload {
9
+ success?: boolean;
10
+ message?: string;
11
+ error?: string;
12
+ [key: string]: unknown;
13
+ }
14
+ export declare function toPythonOutput(response: unknown): PythonOutput;
15
+ export declare function parseStandardResult(response: unknown, tag?: string): TaggedJsonResult<StandardResultPayload>;
16
+ export declare function stripTaggedResultLines(text: string, tag?: string): string;
17
+ export declare function extractTaggedLine(output: string | PythonOutput, prefix: string): string | null;
18
+ //# sourceMappingURL=python-output.d.ts.map