@minded-ai/mindedjs 3.1.46 → 3.1.49

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 (43) hide show
  1. package/dist/browserTask/resolveRpaBrowserSessionOptions.d.ts +13 -0
  2. package/dist/browserTask/resolveRpaBrowserSessionOptions.d.ts.map +1 -0
  3. package/dist/browserTask/resolveRpaBrowserSessionOptions.js +14 -0
  4. package/dist/browserTask/resolveRpaBrowserSessionOptions.js.map +1 -0
  5. package/dist/nodes/addBrowserTaskNode.js +7 -7
  6. package/dist/nodes/addBrowserTaskNode.js.map +1 -1
  7. package/dist/nodes/addPromptNode.d.ts.map +1 -1
  8. package/dist/nodes/addPromptNode.js +7 -20
  9. package/dist/nodes/addPromptNode.js.map +1 -1
  10. package/dist/nodes/addToolRunNode.d.ts.map +1 -1
  11. package/dist/nodes/addToolRunNode.js +8 -4
  12. package/dist/nodes/addToolRunNode.js.map +1 -1
  13. package/dist/platform/config.d.ts +2 -0
  14. package/dist/platform/config.d.ts.map +1 -1
  15. package/dist/platform/config.js +70 -4
  16. package/dist/platform/config.js.map +1 -1
  17. package/dist/platform/mindedConnectionTypes.d.ts +21 -0
  18. package/dist/platform/mindedConnectionTypes.d.ts.map +1 -1
  19. package/dist/platform/mindedConnectionTypes.js +2 -0
  20. package/dist/platform/mindedConnectionTypes.js.map +1 -1
  21. package/dist/platform/toolExecutor.d.ts.map +1 -1
  22. package/dist/platform/toolExecutor.js +7 -6
  23. package/dist/platform/toolExecutor.js.map +1 -1
  24. package/dist/toolsLibrary/distributedLock.d.ts +27 -0
  25. package/dist/toolsLibrary/distributedLock.d.ts.map +1 -0
  26. package/dist/toolsLibrary/distributedLock.js +110 -0
  27. package/dist/toolsLibrary/distributedLock.js.map +1 -0
  28. package/dist/toolsLibrary/extraction.d.ts +2 -2
  29. package/dist/toolsLibrary/index.d.ts +1 -0
  30. package/dist/toolsLibrary/index.d.ts.map +1 -1
  31. package/dist/toolsLibrary/index.js +2 -1
  32. package/dist/toolsLibrary/index.js.map +1 -1
  33. package/docs/low-code-editor/rpa-tools.md +18 -1
  34. package/package.json +1 -1
  35. package/src/browserTask/resolveRpaBrowserSessionOptions.ts +26 -0
  36. package/src/nodes/addBrowserTaskNode.ts +2 -2
  37. package/src/nodes/addPromptNode.ts +7 -22
  38. package/src/nodes/addToolRunNode.ts +8 -3
  39. package/src/platform/config.ts +75 -4
  40. package/src/platform/mindedConnectionTypes.ts +25 -0
  41. package/src/platform/toolExecutor.ts +6 -5
  42. package/src/toolsLibrary/distributedLock.ts +160 -0
  43. package/src/toolsLibrary/index.ts +2 -0
@@ -3,6 +3,7 @@ import { config } from 'dotenv';
3
3
  import { Environment } from '../types/Platform.types';
4
4
  import { BrowserTaskMode } from '../browserTask/types';
5
5
  import { logger } from '../utils/logger';
6
+ import { MindedProxyMode, ProxyConfig, ProxyProvider } from '../types/Tools.types';
6
7
  const path = resolve(__dirname, '../../.env');
7
8
  config({ path });
8
9
 
@@ -18,6 +19,7 @@ type MindedConfig = {
18
19
  elevenLabsKey: string | null;
19
20
  elevenLabsAgentId: string | null;
20
21
  browserTaskMode: BrowserTaskMode;
22
+ proxyConfig: ProxyConfig | null;
21
23
  isDeprioritizedSocket: boolean;
22
24
  };
23
25
 
@@ -37,8 +39,73 @@ const parseBrowserTaskMode = (value: string | undefined): BrowserTaskMode => {
37
39
  return BrowserTaskMode.CLOUD;
38
40
  };
39
41
 
42
+ const parseProxyConfig = (): ProxyConfig | null => {
43
+ const provider = process.env.BROWSER_PROXY_PROVIDER?.trim();
44
+ if (!provider) {
45
+ return null;
46
+ }
47
+
48
+ if (provider === ProxyProvider.MINDED) {
49
+ const mode = process.env.BROWSER_PROXY_MODE?.trim();
50
+ if (mode === MindedProxyMode.TRUSTED_IP) {
51
+ return {
52
+ provider: ProxyProvider.MINDED,
53
+ mode: MindedProxyMode.TRUSTED_IP,
54
+ };
55
+ }
56
+ if (mode === MindedProxyMode.REGION) {
57
+ const countryCode = process.env.BROWSER_PROXY_COUNTRY_CODE?.trim();
58
+ if (!countryCode) {
59
+ logger.warn({
60
+ message: 'BROWSER_PROXY_COUNTRY_CODE is required when BROWSER_PROXY_MODE is region; ignoring proxy config',
61
+ });
62
+ return null;
63
+ }
64
+ return {
65
+ provider: ProxyProvider.MINDED,
66
+ mode: MindedProxyMode.REGION,
67
+ countryCode,
68
+ };
69
+ }
70
+ logger.warn({
71
+ message: 'Invalid BROWSER_PROXY_MODE provided; ignoring proxy config',
72
+ provided: mode,
73
+ allowed: [MindedProxyMode.TRUSTED_IP, MindedProxyMode.REGION],
74
+ });
75
+ return null;
76
+ }
77
+
78
+ if (provider === ProxyProvider.CUSTOM) {
79
+ const server = process.env.BROWSER_PROXY_SERVER?.trim();
80
+ if (!server) {
81
+ logger.warn({
82
+ message: 'BROWSER_PROXY_SERVER is required when BROWSER_PROXY_PROVIDER is custom; ignoring proxy config',
83
+ });
84
+ return null;
85
+ }
86
+ const username = process.env.BROWSER_PROXY_USERNAME?.trim();
87
+ const password = process.env.BROWSER_PROXY_PASSWORD?.trim();
88
+ return {
89
+ provider: ProxyProvider.CUSTOM,
90
+ server,
91
+ ...(username ? { username } : {}),
92
+ ...(password ? { password } : {}),
93
+ };
94
+ }
95
+
96
+ logger.warn({
97
+ message: 'Invalid BROWSER_PROXY_PROVIDER provided; ignoring proxy config',
98
+ provided: provider,
99
+ allowed: [ProxyProvider.MINDED, ProxyProvider.CUSTOM],
100
+ });
101
+ return null;
102
+ };
103
+
40
104
  export const getConfig = (): MindedConfig => {
41
105
  const environment = (process.env.NODE_ENV as Environment) || Environment.DEVELOPMENT;
106
+ const browserTaskMode = parseBrowserTaskMode(process.env.BROWSER_TASK_MODE);
107
+ const proxyConfig = parseProxyConfig();
108
+
42
109
  switch (environment) {
43
110
  case Environment.TEST:
44
111
  return {
@@ -52,7 +119,8 @@ export const getConfig = (): MindedConfig => {
52
119
  dashboardConnected: false,
53
120
  elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
54
121
  elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || null,
55
- browserTaskMode: parseBrowserTaskMode(process.env.BROWSER_TASK_MODE),
122
+ browserTaskMode,
123
+ proxyConfig,
56
124
  isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
57
125
  };
58
126
  case Environment.DEVELOPMENT:
@@ -67,7 +135,8 @@ export const getConfig = (): MindedConfig => {
67
135
  elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
68
136
  dashboardConnected: true,
69
137
  elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye194psezr909nwec27m2t9',
70
- browserTaskMode: parseBrowserTaskMode(process.env.BROWSER_TASK_MODE),
138
+ browserTaskMode,
139
+ proxyConfig,
71
140
  isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
72
141
  };
73
142
  case Environment.STAGING:
@@ -82,7 +151,8 @@ export const getConfig = (): MindedConfig => {
82
151
  elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
83
152
  dashboardConnected: false,
84
153
  elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye1ajkaf17axpcxg220qwcm',
85
- browserTaskMode: parseBrowserTaskMode(process.env.BROWSER_TASK_MODE),
154
+ browserTaskMode,
155
+ proxyConfig,
86
156
  isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
87
157
  };
88
158
  case Environment.PRODUCTION:
@@ -97,7 +167,8 @@ export const getConfig = (): MindedConfig => {
97
167
  elevenLabsKey: process.env.ELEVEN_LABS_API_KEY || null,
98
168
  dashboardConnected: false,
99
169
  elevenLabsAgentId: process.env.ELEVEN_LABS_AGENT_ID || 'agent_01jye1ajkaf17axpcxg220qwcm',
100
- browserTaskMode: parseBrowserTaskMode(process.env.BROWSER_TASK_MODE),
170
+ browserTaskMode,
171
+ proxyConfig,
101
172
  isDeprioritizedSocket: process.env.IS_DEPRIORITIZED_SOCKET === 'true',
102
173
  };
103
174
  }
@@ -18,6 +18,8 @@ export enum mindedConnectionSocketMessageType {
18
18
  SAVE_STORAGE_RECORD = 'save-storage-record',
19
19
  GET_STORAGE_RECORDS = 'get-storage-records',
20
20
  DELETE_STORAGE_RECORD = 'delete-storage-record',
21
+ ACQUIRE_DISTRIBUTED_LOCK = 'acquire-distributed-lock',
22
+ RELEASE_DISTRIBUTED_LOCK = 'release-distributed-lock',
21
23
  GET_AGENT_CONFIGURATION = 'get-agent-configuration',
22
24
  GET_FLOWS = 'get-flows',
23
25
  GET_PLAYBOOKS = 'get-playbooks',
@@ -99,6 +101,8 @@ export type mindedConnectionSocketMessageTypeMap = {
99
101
  [mindedConnectionSocketMessageType.SAVE_STORAGE_RECORD]: SaveStorageRecordRequest;
100
102
  [mindedConnectionSocketMessageType.GET_STORAGE_RECORDS]: GetStorageRecordsRequest;
101
103
  [mindedConnectionSocketMessageType.DELETE_STORAGE_RECORD]: DeleteStorageRecordRequest;
104
+ [mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK]: AcquireDistributedLockRequest;
105
+ [mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK]: ReleaseDistributedLockRequest;
102
106
  [mindedConnectionSocketMessageType.GET_FLOWS]: BasemindedConnectionSocketMessage;
103
107
  [mindedConnectionSocketMessageType.GET_PLAYBOOKS]: BasemindedConnectionSocketMessage;
104
108
  [mindedConnectionSocketMessageType.INVOKE]: InvokeMessage;
@@ -813,6 +817,27 @@ export interface DeleteStorageRecordResponse extends BaseSdkConnectionSocketMess
813
817
  success?: boolean;
814
818
  }
815
819
 
820
+ export interface AcquireDistributedLockRequest extends BasemindedConnectionSocketMessage {
821
+ type: mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK;
822
+ key: string;
823
+ ttlSeconds?: number;
824
+ }
825
+
826
+ export interface AcquireDistributedLockResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
827
+ acquired?: boolean;
828
+ lockId?: string;
829
+ }
830
+
831
+ export interface ReleaseDistributedLockRequest extends BasemindedConnectionSocketMessage {
832
+ type: mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK;
833
+ key: string;
834
+ lockId: string;
835
+ }
836
+
837
+ export interface ReleaseDistributedLockResponse extends BaseSdkConnectionSocketMessageResponseCallbackAck {
838
+ released?: boolean;
839
+ }
840
+
816
841
  export interface RPAErrorUploadRequest extends BasemindedConnectionSocketMessage {
817
842
  type: mindedConnectionSocketMessageType.RPA_ERROR_UPLOAD;
818
843
  sessionId: string;
@@ -2,7 +2,7 @@ import { Tool } from '../types/Tools.types';
2
2
  import { Agent } from '../agent';
3
3
  import { logger } from '../utils/logger';
4
4
  import { withBrowserSession } from '../toolsLibrary/withBrowserSession';
5
- import { getConfig } from './config';
5
+ import { resolveRpaBrowserSessionOptions } from '../browserTask/resolveRpaBrowserSessionOptions';
6
6
 
7
7
  export interface ToolExecutionRequest {
8
8
  toolName: string;
@@ -86,9 +86,10 @@ export class ToolExecutor {
86
86
 
87
87
  // Check if this is an RPA tool
88
88
  if (tool.type === 'rpa') {
89
- const configBrowserTaskMode = getConfig().browserTaskMode;
90
- // Use tool's browserTaskMode if provided, otherwise fall back to config
91
- const browserTaskMode = tool.browserTaskMode ?? configBrowserTaskMode;
89
+ const { browserTaskMode, proxyConfig } = resolveRpaBrowserSessionOptions({
90
+ toolBrowserTaskMode: tool.browserTaskMode,
91
+ toolProxyConfig: tool.proxyConfig,
92
+ });
92
93
 
93
94
  // Wrap with browser session and screenshot capture
94
95
  const { result, breakpointHit, breakpointInfo } = await withBrowserSession(
@@ -96,7 +97,7 @@ export class ToolExecutor {
96
97
  sessionId,
97
98
  browserTaskMode,
98
99
  toolCallId: requestId, // Use requestId as toolCallId for tracking
99
- proxyConfig: tool.proxyConfig,
100
+ proxyConfig,
100
101
  toolName,
101
102
  persistSession: tool.persistSession,
102
103
  },
@@ -0,0 +1,160 @@
1
+ import { awaitEmit } from '../platform/mindedConnection';
2
+ import {
3
+ mindedConnectionSocketMessageType,
4
+ AcquireDistributedLockRequest,
5
+ AcquireDistributedLockResponse,
6
+ ReleaseDistributedLockRequest,
7
+ ReleaseDistributedLockResponse,
8
+ } from '../platform/mindedConnectionTypes';
9
+ import { logger } from '../utils/logger';
10
+ import { wait } from '../utils/wait';
11
+
12
+ const LOCK_KEY_PATTERN = /^[a-zA-Z0-9:_-]{1,128}$/;
13
+ const DEFAULT_TTL_SECONDS = 90;
14
+ const DEFAULT_WAIT_MS = 60_000;
15
+ const DEFAULT_RETRY_INTERVAL_MS = 500;
16
+ const SOCKET_TIMEOUT_MS = 10_000;
17
+
18
+ interface AcquireLockParams {
19
+ key: string;
20
+ ttlSeconds?: number;
21
+ waitMs?: number;
22
+ retryIntervalMs?: number;
23
+ sessionId?: string;
24
+ }
25
+
26
+ interface ReleaseLockParams {
27
+ key: string;
28
+ lockId: string;
29
+ sessionId?: string;
30
+ }
31
+
32
+ interface WithLockParams {
33
+ key: string;
34
+ ttlSeconds?: number;
35
+ waitMs?: number;
36
+ retryIntervalMs?: number;
37
+ sessionId?: string;
38
+ }
39
+
40
+ export class DistributedLockTimeoutError extends Error {
41
+ constructor(key: string, waitMs: number) {
42
+ super(`Timed out waiting ${waitMs}ms to acquire distributed lock "${key}"`);
43
+ this.name = 'DistributedLockTimeoutError';
44
+ }
45
+ }
46
+
47
+ const assertValidLockKey = (key: string) => {
48
+ if (!LOCK_KEY_PATTERN.test(key)) {
49
+ throw new Error('Lock key must be 1-128 characters of letters, numbers, colon, underscore, or hyphen');
50
+ }
51
+ };
52
+
53
+ const tryAcquireOnce = async ({ key, ttlSeconds }: { key: string; ttlSeconds: number }): Promise<string | null> => {
54
+ const request: AcquireDistributedLockRequest = {
55
+ type: mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK,
56
+ key,
57
+ ttlSeconds,
58
+ };
59
+
60
+ const response = await awaitEmit<AcquireDistributedLockRequest, AcquireDistributedLockResponse>(
61
+ mindedConnectionSocketMessageType.ACQUIRE_DISTRIBUTED_LOCK,
62
+ request,
63
+ SOCKET_TIMEOUT_MS,
64
+ );
65
+
66
+ if (response.error) {
67
+ throw new Error(response.error);
68
+ }
69
+
70
+ if (response.acquired === true && response.lockId) {
71
+ return response.lockId;
72
+ }
73
+
74
+ return null;
75
+ };
76
+
77
+ export const acquireLock = async ({
78
+ key,
79
+ ttlSeconds = DEFAULT_TTL_SECONDS,
80
+ waitMs = DEFAULT_WAIT_MS,
81
+ retryIntervalMs = DEFAULT_RETRY_INTERVAL_MS,
82
+ sessionId,
83
+ }: AcquireLockParams): Promise<string> => {
84
+ assertValidLockKey(key);
85
+ const deadline = Date.now() + waitMs;
86
+
87
+ const initialLockId = await tryAcquireOnce({ key, ttlSeconds });
88
+ if (initialLockId !== null) {
89
+ logger.info({
90
+ message: 'Acquired distributed lock',
91
+ key,
92
+ sessionId,
93
+ });
94
+ return initialLockId;
95
+ }
96
+
97
+ while (Date.now() < deadline) {
98
+ await wait(retryIntervalMs);
99
+ const lockId = await tryAcquireOnce({ key, ttlSeconds });
100
+ if (lockId !== null) {
101
+ logger.info({
102
+ message: 'Acquired distributed lock',
103
+ key,
104
+ sessionId,
105
+ });
106
+ return lockId;
107
+ }
108
+ }
109
+
110
+ throw new DistributedLockTimeoutError(key, waitMs);
111
+ };
112
+
113
+ export const releaseLock = async ({ key, lockId, sessionId }: ReleaseLockParams): Promise<void> => {
114
+ assertValidLockKey(key);
115
+ if (!lockId) {
116
+ throw new Error('lockId is required in releaseLock params');
117
+ }
118
+
119
+ const request: ReleaseDistributedLockRequest = {
120
+ type: mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK,
121
+ key,
122
+ lockId,
123
+ };
124
+
125
+ const response = await awaitEmit<ReleaseDistributedLockRequest, ReleaseDistributedLockResponse>(
126
+ mindedConnectionSocketMessageType.RELEASE_DISTRIBUTED_LOCK,
127
+ request,
128
+ SOCKET_TIMEOUT_MS,
129
+ );
130
+
131
+ if (response.error) {
132
+ throw new Error(response.error);
133
+ }
134
+
135
+ if (response.released === false) {
136
+ logger.warn({
137
+ message: 'Distributed lock was not released; it may have expired',
138
+ key,
139
+ sessionId,
140
+ });
141
+ }
142
+ };
143
+
144
+ export const withLock = async <T>(params: WithLockParams, callback: () => Promise<T>): Promise<T> => {
145
+ const lockId = await acquireLock(params);
146
+ try {
147
+ return await callback();
148
+ } finally {
149
+ try {
150
+ await releaseLock({ key: params.key, lockId, sessionId: params.sessionId });
151
+ } catch (error) {
152
+ logger.warn({
153
+ message: 'Failed to release distributed lock',
154
+ key: params.key,
155
+ sessionId: params.sessionId,
156
+ error,
157
+ });
158
+ }
159
+ }
160
+ };
@@ -4,6 +4,8 @@ import * as extraction from './extraction';
4
4
  import * as resolveCaptcha from './resolveCaptcha';
5
5
  import * as storage from './storage';
6
6
 
7
+ export * as lock from './distributedLock';
8
+
7
9
  // Export all tools as a collection for easy discovery
8
10
  export const tools = {
9
11
  'minded-parse-documents': parseDocument,