praisonai 1.7.1 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -115,6 +115,32 @@ class MCPSecurity {
115
115
  return config.requests;
116
116
  return Math.max(0, config.requests - state.count);
117
117
  }
118
+ /**
119
+ * Validate credentials for a given auth method (fail closed by default)
120
+ */
121
+ async validateCredentials(auth, token) {
122
+ switch (auth.method) {
123
+ case 'none':
124
+ return true;
125
+ case 'api-key':
126
+ case 'bearer':
127
+ if (auth.validate) {
128
+ return auth.validate(token);
129
+ }
130
+ if (this.apiKeys.size === 0) {
131
+ return false;
132
+ }
133
+ return this.validateApiKey(token);
134
+ case 'basic':
135
+ case 'oauth':
136
+ if (!auth.validate) {
137
+ return false;
138
+ }
139
+ return auth.validate(token);
140
+ default:
141
+ return false;
142
+ }
143
+ }
118
144
  /**
119
145
  * Match policy against request
120
146
  */
@@ -141,19 +167,16 @@ class MCPSecurity {
141
167
  case 'allow':
142
168
  return { allowed: true };
143
169
  case 'authenticate':
144
- if (!policy.auth)
145
- return { allowed: true };
170
+ if (!policy.auth) {
171
+ return { allowed: false, reason: 'Authentication policy misconfigured' };
172
+ }
146
173
  const token = request.headers ? this.extractToken(request.headers) : null;
147
- if (!token) {
174
+ if (!token || !token.trim()) {
148
175
  return { allowed: false, reason: 'Authentication required' };
149
176
  }
150
- if (policy.auth.method === 'api-key' || policy.auth.method === 'bearer') {
151
- const valid = policy.auth.validate
152
- ? await policy.auth.validate(token)
153
- : this.validateApiKey(token);
154
- if (!valid) {
155
- return { allowed: false, reason: 'Invalid credentials' };
156
- }
177
+ const valid = await this.validateCredentials(policy.auth, token);
178
+ if (!valid) {
179
+ return { allowed: false, reason: 'Invalid credentials' };
157
180
  }
158
181
  return { allowed: true, context: { authenticated: true } };
159
182
  case 'rate-limit':
@@ -85,6 +85,8 @@ export interface MCPServerConfig {
85
85
  port?: number | null;
86
86
  /** Enable logging */
87
87
  logging?: boolean;
88
+ /** Optional bearer token for HTTP transport (or set PRAISONAI_MCP_AUTH_TOKEN) */
89
+ authToken?: string;
88
90
  }
89
91
  /**
90
92
  * MCP Request
@@ -121,6 +123,7 @@ export declare class MCPServer {
121
123
  private logging;
122
124
  private running;
123
125
  private httpServer;
126
+ private authToken?;
124
127
  constructor(config?: MCPServerConfig);
125
128
  /**
126
129
  * Register a tool
@@ -174,6 +177,10 @@ export declare class MCPServer {
174
177
  * Start stdio transport
175
178
  */
176
179
  startStdio(): Promise<void>;
180
+ /**
181
+ * Verify HTTP bearer token when authToken is configured
182
+ */
183
+ private verifyHttpAuth;
177
184
  /**
178
185
  * Start HTTP transport
179
186
  */
@@ -65,6 +65,7 @@ class MCPServer {
65
65
  this.resources = new Map();
66
66
  this.prompts = new Map();
67
67
  this.logging = config.logging ?? false;
68
+ this.authToken = config.authToken ?? process.env.PRAISONAI_MCP_AUTH_TOKEN ?? undefined;
68
69
  // Register initial tools
69
70
  if (config.tools) {
70
71
  for (const tool of config.tools) {
@@ -315,6 +316,25 @@ class MCPServer {
315
316
  this.running = false;
316
317
  });
317
318
  }
319
+ /**
320
+ * Verify HTTP bearer token when authToken is configured
321
+ */
322
+ verifyHttpAuth(req) {
323
+ if (!this.authToken) {
324
+ return true;
325
+ }
326
+ const authHeader = req.headers.authorization ?? req.headers['Authorization'];
327
+ if (typeof authHeader === 'string') {
328
+ if (authHeader.startsWith('Bearer ') && authHeader.slice(7) === this.authToken) {
329
+ return true;
330
+ }
331
+ }
332
+ const xAuth = req.headers['x-auth-token'] ?? req.headers['X-Auth-Token'];
333
+ if (typeof xAuth === 'string' && xAuth === this.authToken) {
334
+ return true;
335
+ }
336
+ return false;
337
+ }
318
338
  /**
319
339
  * Start HTTP transport
320
340
  */
@@ -325,6 +345,11 @@ class MCPServer {
325
345
  const http = await Promise.resolve().then(() => __importStar(require('http')));
326
346
  this.httpServer = http.createServer(async (req, res) => {
327
347
  if (req.method === 'POST') {
348
+ if (!this.verifyHttpAuth(req)) {
349
+ res.writeHead(401, { 'Content-Type': 'application/json' });
350
+ res.end(JSON.stringify({ error: 'Unauthorized' }));
351
+ return;
352
+ }
328
353
  let body = '';
329
354
  req.on('data', chunk => body += chunk);
330
355
  req.on('end', async () => {
@@ -112,6 +112,25 @@ class AgentOS {
112
112
  next();
113
113
  });
114
114
  }
115
+ // Optional API key middleware (except /health)
116
+ if (this.config.apiKey) {
117
+ app.use((req, res, next) => {
118
+ if (req.path === '/health') {
119
+ return next();
120
+ }
121
+ const authHeader = req.headers.authorization;
122
+ if (typeof authHeader === 'string' && authHeader.startsWith('Bearer ')) {
123
+ if (authHeader.slice(7) === this.config.apiKey) {
124
+ return next();
125
+ }
126
+ }
127
+ const xAuth = req.headers['x-auth-token'] ?? req.headers['X-Auth-Token'];
128
+ if (typeof xAuth === 'string' && xAuth === this.config.apiKey) {
129
+ return next();
130
+ }
131
+ return res.status(401).json({ error: 'Unauthorized' });
132
+ });
133
+ }
115
134
  // Register routes
116
135
  this._registerRoutes(app);
117
136
  return app;
@@ -45,6 +45,8 @@ export interface AgentOSConfig {
45
45
  timeout?: number;
46
46
  /** Additional metadata for the app */
47
47
  metadata?: Record<string, any>;
48
+ /** Optional API key for route protection (or set PRAISONAI_AGENTOS_API_KEY) */
49
+ apiKey?: string;
48
50
  }
49
51
  /**
50
52
  * Default configuration values for AgentOS.
package/dist/os/config.js CHANGED
@@ -33,15 +33,18 @@ exports.DEFAULT_AGENTOS_CONFIG = {
33
33
  logLevel: 'info',
34
34
  workers: 1,
35
35
  timeout: 60,
36
+ apiKey: '',
36
37
  metadata: {},
37
38
  };
38
39
  /**
39
40
  * Merge user config with defaults.
40
41
  */
41
42
  function mergeConfig(userConfig) {
43
+ const apiKey = userConfig?.apiKey ?? process.env.PRAISONAI_AGENTOS_API_KEY ?? '';
42
44
  return {
43
45
  ...exports.DEFAULT_AGENTOS_CONFIG,
44
46
  ...userConfig,
47
+ apiKey,
45
48
  metadata: {
46
49
  ...exports.DEFAULT_AGENTOS_CONFIG.metadata,
47
50
  ...userConfig?.metadata,
@@ -9,6 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.CODE_MODE_METADATA = void 0;
10
10
  exports.codeMode = codeMode;
11
11
  exports.createCodeModeTool = createCodeModeTool;
12
+ const node_vm_1 = require("node:vm");
12
13
  exports.CODE_MODE_METADATA = {
13
14
  id: 'code-mode',
14
15
  displayName: 'Code Mode',
@@ -69,6 +70,10 @@ function codeMode(config) {
69
70
  /import\s+.*from\s+['"]child_process['"]/,
70
71
  /process\.exit/,
71
72
  /eval\s*\(/,
73
+ /Function\s*\(/,
74
+ /\.constructor/,
75
+ /globalThis/,
76
+ /\bprocess\b/,
72
77
  ];
73
78
  if (!settings.allowNetwork) {
74
79
  blockedPatterns.push(/require\s*\(\s*['"]http['"]\s*\)/, /require\s*\(\s*['"]https['"]\s*\)/, /require\s*\(\s*['"]net['"]\s*\)/, /fetch\s*\(/);
@@ -101,37 +106,32 @@ function codeMode(config) {
101
106
  }
102
107
  }
103
108
  try {
104
- // Create a sandboxed execution context
105
- // In a real implementation, this would use a proper sandbox like vm2 or isolated-vm
106
- // For now, we provide a safe execution wrapper
107
- const sandbox = {
109
+ const stdout = [];
110
+ const stderr = [];
111
+ const sandboxContext = {
108
112
  console: {
109
113
  log: (...args) => stdout.push(args.map(String).join(' ')),
110
114
  error: (...args) => stderr.push(args.map(String).join(' ')),
111
115
  warn: (...args) => stderr.push(args.map(String).join(' ')),
112
116
  },
113
- setTimeout: undefined,
114
- setInterval: undefined,
115
- setImmediate: undefined,
116
- process: undefined,
117
- require: undefined,
118
117
  __dirname: '/sandbox',
119
118
  __filename: '/sandbox/index.js',
120
119
  env: env || {},
121
120
  files: files || {},
122
121
  };
123
- const stdout = [];
124
- const stderr = [];
125
- // Execute with timeout
126
122
  const timeoutPromise = new Promise((_, reject) => {
127
123
  setTimeout(() => reject(new Error('Execution timeout')), settings.timeoutMs);
128
124
  });
129
125
  const executePromise = new Promise((resolve, reject) => {
130
126
  try {
131
- // Create a function from the code
132
- const fn = new Function('sandbox', `with (sandbox) { ${code} }`);
133
- const result = fn(sandbox);
134
- resolve(String(result ?? ''));
127
+ const wrappedCode = `(async function() { ${code} })()`;
128
+ const result = (0, node_vm_1.runInNewContext)(wrappedCode, sandboxContext, {
129
+ timeout: settings.timeoutMs,
130
+ displayErrors: true,
131
+ });
132
+ Promise.resolve(result)
133
+ .then((value) => resolve(String(value ?? '')))
134
+ .catch(reject);
135
135
  }
136
136
  catch (error) {
137
137
  reject(error);
@@ -1,8 +1,11 @@
1
1
  export { BaseTool, ToolResult, ToolValidationError, validateTool, createTool, type ToolParameters } from './base';
2
- export * from './decorator';
2
+ export { tool, FunctionTool, ToolRegistry, getRegistry, registerTool, getTool, type ToolConfig, type ToolContext, } from './decorator';
3
3
  export * from './arxivTools';
4
4
  export * from './mcpSse';
5
- export * from './registry';
5
+ export { ToolsRegistry, getToolsRegistry, createToolsRegistry, resetToolsRegistry, get_registry, get_tool, register_tool, validate_tool, } from './registry';
6
+ export type { ToolExecutionContext, ToolLimits, RedactionHooks, ToolLogger, ToolCapabilities, InstallHints, ToolMetadata, ToolExecutionResult, PraisonTool, ToolParameterSchema, ToolParameterProperty, ToolMiddleware, ToolHooks, ToolFactory, RegisteredTool, ToolInstallStatus, } from './registry';
7
+ export { MissingDependencyError, MissingEnvVarError, BudgetExceededError } from './registry';
8
+ export { createLoggingMiddleware, createTimeoutMiddleware, createRedactionMiddleware, createRateLimitMiddleware, createRetryMiddleware, createTracingMiddleware, createValidationMiddleware, composeMiddleware, } from './registry';
6
9
  export * from './builtins';
7
10
  export { tools, registerBuiltinTools } from './tools';
8
11
  export type { default as ToolsFacade } from './tools';
@@ -14,20 +14,47 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.createDelegator = exports.createSubagentTools = exports.createSubagentTool = exports.SubagentTool = exports.registerBuiltinTools = exports.tools = exports.createTool = exports.validateTool = exports.ToolValidationError = exports.BaseTool = void 0;
17
+ exports.createDelegator = exports.createSubagentTools = exports.createSubagentTool = exports.SubagentTool = exports.registerBuiltinTools = exports.tools = exports.composeMiddleware = exports.createValidationMiddleware = exports.createTracingMiddleware = exports.createRetryMiddleware = exports.createRateLimitMiddleware = exports.createRedactionMiddleware = exports.createTimeoutMiddleware = exports.createLoggingMiddleware = exports.BudgetExceededError = exports.MissingEnvVarError = exports.MissingDependencyError = exports.validate_tool = exports.register_tool = exports.get_tool = exports.get_registry = exports.resetToolsRegistry = exports.createToolsRegistry = exports.getToolsRegistry = exports.ToolsRegistry = exports.getTool = exports.registerTool = exports.getRegistry = exports.ToolRegistry = exports.FunctionTool = exports.tool = exports.createTool = exports.validateTool = exports.ToolValidationError = exports.BaseTool = void 0;
18
18
  // Export base tool interfaces and classes
19
19
  var base_1 = require("./base");
20
20
  Object.defineProperty(exports, "BaseTool", { enumerable: true, get: function () { return base_1.BaseTool; } });
21
21
  Object.defineProperty(exports, "ToolValidationError", { enumerable: true, get: function () { return base_1.ToolValidationError; } });
22
22
  Object.defineProperty(exports, "validateTool", { enumerable: true, get: function () { return base_1.validateTool; } });
23
23
  Object.defineProperty(exports, "createTool", { enumerable: true, get: function () { return base_1.createTool; } });
24
- // Export decorator and registry (legacy)
25
- __exportStar(require("./decorator"), exports);
24
+ // Legacy @tool decorator registry (camelCase names reserved for this API)
25
+ var decorator_1 = require("./decorator");
26
+ Object.defineProperty(exports, "tool", { enumerable: true, get: function () { return decorator_1.tool; } });
27
+ Object.defineProperty(exports, "FunctionTool", { enumerable: true, get: function () { return decorator_1.FunctionTool; } });
28
+ Object.defineProperty(exports, "ToolRegistry", { enumerable: true, get: function () { return decorator_1.ToolRegistry; } });
29
+ Object.defineProperty(exports, "getRegistry", { enumerable: true, get: function () { return decorator_1.getRegistry; } });
30
+ Object.defineProperty(exports, "registerTool", { enumerable: true, get: function () { return decorator_1.registerTool; } });
31
+ Object.defineProperty(exports, "getTool", { enumerable: true, get: function () { return decorator_1.getTool; } });
26
32
  // Export all tool modules
27
33
  __exportStar(require("./arxivTools"), exports);
28
34
  __exportStar(require("./mcpSse"), exports);
29
- // Export new registry system
30
- __exportStar(require("./registry"), exports);
35
+ // New AI SDK tools registry — snake_case parity names (avoid camelCase clash with decorator)
36
+ var registry_1 = require("./registry");
37
+ Object.defineProperty(exports, "ToolsRegistry", { enumerable: true, get: function () { return registry_1.ToolsRegistry; } });
38
+ Object.defineProperty(exports, "getToolsRegistry", { enumerable: true, get: function () { return registry_1.getToolsRegistry; } });
39
+ Object.defineProperty(exports, "createToolsRegistry", { enumerable: true, get: function () { return registry_1.createToolsRegistry; } });
40
+ Object.defineProperty(exports, "resetToolsRegistry", { enumerable: true, get: function () { return registry_1.resetToolsRegistry; } });
41
+ Object.defineProperty(exports, "get_registry", { enumerable: true, get: function () { return registry_1.get_registry; } });
42
+ Object.defineProperty(exports, "get_tool", { enumerable: true, get: function () { return registry_1.get_tool; } });
43
+ Object.defineProperty(exports, "register_tool", { enumerable: true, get: function () { return registry_1.register_tool; } });
44
+ Object.defineProperty(exports, "validate_tool", { enumerable: true, get: function () { return registry_1.validate_tool; } });
45
+ var registry_2 = require("./registry");
46
+ Object.defineProperty(exports, "MissingDependencyError", { enumerable: true, get: function () { return registry_2.MissingDependencyError; } });
47
+ Object.defineProperty(exports, "MissingEnvVarError", { enumerable: true, get: function () { return registry_2.MissingEnvVarError; } });
48
+ Object.defineProperty(exports, "BudgetExceededError", { enumerable: true, get: function () { return registry_2.BudgetExceededError; } });
49
+ var registry_3 = require("./registry");
50
+ Object.defineProperty(exports, "createLoggingMiddleware", { enumerable: true, get: function () { return registry_3.createLoggingMiddleware; } });
51
+ Object.defineProperty(exports, "createTimeoutMiddleware", { enumerable: true, get: function () { return registry_3.createTimeoutMiddleware; } });
52
+ Object.defineProperty(exports, "createRedactionMiddleware", { enumerable: true, get: function () { return registry_3.createRedactionMiddleware; } });
53
+ Object.defineProperty(exports, "createRateLimitMiddleware", { enumerable: true, get: function () { return registry_3.createRateLimitMiddleware; } });
54
+ Object.defineProperty(exports, "createRetryMiddleware", { enumerable: true, get: function () { return registry_3.createRetryMiddleware; } });
55
+ Object.defineProperty(exports, "createTracingMiddleware", { enumerable: true, get: function () { return registry_3.createTracingMiddleware; } });
56
+ Object.defineProperty(exports, "createValidationMiddleware", { enumerable: true, get: function () { return registry_3.createValidationMiddleware; } });
57
+ Object.defineProperty(exports, "composeMiddleware", { enumerable: true, get: function () { return registry_3.composeMiddleware; } });
31
58
  // Export built-in tools
32
59
  __exportStar(require("./builtins"), exports);
33
60
  // Export tools facade
@@ -4,6 +4,6 @@
4
4
  * Lazy-loaded exports for the tools registry system.
5
5
  */
6
6
  export type { ToolExecutionContext, ToolLimits, RedactionHooks, ToolLogger, ToolCapabilities, InstallHints, ToolMetadata, ToolExecutionResult, PraisonTool, ToolParameterSchema, ToolParameterProperty, ToolMiddleware, ToolHooks, ToolFactory, RegisteredTool, ToolInstallStatus, } from './types';
7
- export { MissingDependencyError, MissingEnvVarError } from './types';
8
- export { ToolsRegistry, getToolsRegistry, createToolsRegistry, resetToolsRegistry, } from './registry';
7
+ export { MissingDependencyError, MissingEnvVarError, BudgetExceededError } from './types';
8
+ export { ToolsRegistry, getToolsRegistry, createToolsRegistry, resetToolsRegistry, get_registry, getRegistry, get_tool, getTool, register_tool, registerTool, validate_tool, validateTool, } from './registry';
9
9
  export { createLoggingMiddleware, createTimeoutMiddleware, createRedactionMiddleware, createRateLimitMiddleware, createRetryMiddleware, createTracingMiddleware, createValidationMiddleware, composeMiddleware, } from './middleware';
@@ -5,17 +5,26 @@
5
5
  * Lazy-loaded exports for the tools registry system.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.composeMiddleware = exports.createValidationMiddleware = exports.createTracingMiddleware = exports.createRetryMiddleware = exports.createRateLimitMiddleware = exports.createRedactionMiddleware = exports.createTimeoutMiddleware = exports.createLoggingMiddleware = exports.resetToolsRegistry = exports.createToolsRegistry = exports.getToolsRegistry = exports.ToolsRegistry = exports.MissingEnvVarError = exports.MissingDependencyError = void 0;
8
+ exports.composeMiddleware = exports.createValidationMiddleware = exports.createTracingMiddleware = exports.createRetryMiddleware = exports.createRateLimitMiddleware = exports.createRedactionMiddleware = exports.createTimeoutMiddleware = exports.createLoggingMiddleware = exports.validateTool = exports.validate_tool = exports.registerTool = exports.register_tool = exports.getTool = exports.get_tool = exports.getRegistry = exports.get_registry = exports.resetToolsRegistry = exports.createToolsRegistry = exports.getToolsRegistry = exports.ToolsRegistry = exports.BudgetExceededError = exports.MissingEnvVarError = exports.MissingDependencyError = void 0;
9
9
  // Errors
10
10
  var types_1 = require("./types");
11
11
  Object.defineProperty(exports, "MissingDependencyError", { enumerable: true, get: function () { return types_1.MissingDependencyError; } });
12
12
  Object.defineProperty(exports, "MissingEnvVarError", { enumerable: true, get: function () { return types_1.MissingEnvVarError; } });
13
+ Object.defineProperty(exports, "BudgetExceededError", { enumerable: true, get: function () { return types_1.BudgetExceededError; } });
13
14
  // Registry
14
15
  var registry_1 = require("./registry");
15
16
  Object.defineProperty(exports, "ToolsRegistry", { enumerable: true, get: function () { return registry_1.ToolsRegistry; } });
16
17
  Object.defineProperty(exports, "getToolsRegistry", { enumerable: true, get: function () { return registry_1.getToolsRegistry; } });
17
18
  Object.defineProperty(exports, "createToolsRegistry", { enumerable: true, get: function () { return registry_1.createToolsRegistry; } });
18
19
  Object.defineProperty(exports, "resetToolsRegistry", { enumerable: true, get: function () { return registry_1.resetToolsRegistry; } });
20
+ Object.defineProperty(exports, "get_registry", { enumerable: true, get: function () { return registry_1.get_registry; } });
21
+ Object.defineProperty(exports, "getRegistry", { enumerable: true, get: function () { return registry_1.getRegistry; } });
22
+ Object.defineProperty(exports, "get_tool", { enumerable: true, get: function () { return registry_1.get_tool; } });
23
+ Object.defineProperty(exports, "getTool", { enumerable: true, get: function () { return registry_1.getTool; } });
24
+ Object.defineProperty(exports, "register_tool", { enumerable: true, get: function () { return registry_1.register_tool; } });
25
+ Object.defineProperty(exports, "registerTool", { enumerable: true, get: function () { return registry_1.registerTool; } });
26
+ Object.defineProperty(exports, "validate_tool", { enumerable: true, get: function () { return registry_1.validate_tool; } });
27
+ Object.defineProperty(exports, "validateTool", { enumerable: true, get: function () { return registry_1.validateTool; } });
19
28
  // Middleware
20
29
  var middleware_1 = require("./middleware");
21
30
  Object.defineProperty(exports, "createLoggingMiddleware", { enumerable: true, get: function () { return middleware_1.createLoggingMiddleware; } });
@@ -90,3 +90,36 @@ export declare function createToolsRegistry(): ToolsRegistry;
90
90
  * Reset the global registry (mainly for testing)
91
91
  */
92
92
  export declare function resetToolsRegistry(): void;
93
+ /**
94
+ * Get the global registry instance (alias for getToolsRegistry)
95
+ * For Python SDK parity: get_registry()
96
+ */
97
+ export declare function get_registry(): ToolsRegistry;
98
+ /** camelCase alias for get_registry — idiomatic TypeScript */
99
+ export declare const getRegistry: typeof get_registry;
100
+ /**
101
+ * Get a single tool by name from the global registry
102
+ * For Python SDK parity: get_tool()
103
+ */
104
+ export declare function get_tool<TConfig = unknown, TInput = unknown, TOutput = unknown>(id: string, config?: TConfig): PraisonTool<TInput, TOutput> | null;
105
+ /** camelCase alias for get_tool — idiomatic TypeScript */
106
+ export declare const getTool: typeof get_tool;
107
+ /**
108
+ * Register a tool with the global registry
109
+ * For Python SDK parity: register_tool()
110
+ */
111
+ export declare function register_tool(metadata: ToolMetadata, factory: ToolFactory): void;
112
+ /** camelCase alias for register_tool — idiomatic TypeScript */
113
+ export declare const registerTool: typeof register_tool;
114
+ /**
115
+ * Validate a tool's configuration and dependencies
116
+ * For Python SDK parity: validate_tool()
117
+ */
118
+ export declare function validate_tool(id: string): Promise<{
119
+ valid: boolean;
120
+ installed: boolean;
121
+ missingEnvVars: string[];
122
+ errors: string[];
123
+ }>;
124
+ /** camelCase alias for validate_tool — idiomatic TypeScript */
125
+ export declare const validateTool: typeof validate_tool;
@@ -39,10 +39,14 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  };
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.ToolsRegistry = void 0;
42
+ exports.validateTool = exports.registerTool = exports.getTool = exports.getRegistry = exports.ToolsRegistry = void 0;
43
43
  exports.getToolsRegistry = getToolsRegistry;
44
44
  exports.createToolsRegistry = createToolsRegistry;
45
45
  exports.resetToolsRegistry = resetToolsRegistry;
46
+ exports.get_registry = get_registry;
47
+ exports.get_tool = get_tool;
48
+ exports.register_tool = register_tool;
49
+ exports.validate_tool = validate_tool;
46
50
  /**
47
51
  * Tools Registry - Manages tool registration, lookup, and instantiation
48
52
  */
@@ -278,3 +282,77 @@ function resetToolsRegistry() {
278
282
  }
279
283
  globalRegistry = null;
280
284
  }
285
+ /**
286
+ * Get the global registry instance (alias for getToolsRegistry)
287
+ * For Python SDK parity: get_registry()
288
+ */
289
+ function get_registry() {
290
+ return getToolsRegistry();
291
+ }
292
+ /** camelCase alias for get_registry — idiomatic TypeScript */
293
+ exports.getRegistry = get_registry;
294
+ /**
295
+ * Get a single tool by name from the global registry
296
+ * For Python SDK parity: get_tool()
297
+ */
298
+ function get_tool(id, config) {
299
+ try {
300
+ const registry = getToolsRegistry();
301
+ return registry.create(id, config);
302
+ }
303
+ catch {
304
+ return null;
305
+ }
306
+ }
307
+ /** camelCase alias for get_tool — idiomatic TypeScript */
308
+ exports.getTool = get_tool;
309
+ /**
310
+ * Register a tool with the global registry
311
+ * For Python SDK parity: register_tool()
312
+ */
313
+ function register_tool(metadata, factory) {
314
+ const registry = getToolsRegistry();
315
+ registry.register(metadata, factory);
316
+ }
317
+ /** camelCase alias for register_tool — idiomatic TypeScript */
318
+ exports.registerTool = register_tool;
319
+ /**
320
+ * Validate a tool's configuration and dependencies
321
+ * For Python SDK parity: validate_tool()
322
+ */
323
+ async function validate_tool(id) {
324
+ const registry = getToolsRegistry();
325
+ if (!registry.has(id)) {
326
+ return {
327
+ valid: false,
328
+ installed: false,
329
+ missingEnvVars: [],
330
+ errors: [`Tool "${id}" is not registered`]
331
+ };
332
+ }
333
+ const status = await registry.getInstallStatus(id);
334
+ if (!status) {
335
+ return {
336
+ valid: false,
337
+ installed: false,
338
+ missingEnvVars: [],
339
+ errors: [`Failed to get status for tool "${id}"`]
340
+ };
341
+ }
342
+ const errors = [];
343
+ if (!status.installed) {
344
+ const installCmd = status.installCommand ?? `npm install ${registry.getMetadata(id)?.packageName ?? id}`;
345
+ errors.push(`Package dependency not installed. Run: ${installCmd}`);
346
+ }
347
+ if (status.missingEnvVars.length > 0) {
348
+ errors.push(`Missing environment variables: ${status.missingEnvVars.join(', ')}`);
349
+ }
350
+ return {
351
+ valid: status.installed && status.missingEnvVars.length === 0,
352
+ installed: status.installed,
353
+ missingEnvVars: status.missingEnvVars,
354
+ errors
355
+ };
356
+ }
357
+ /** camelCase alias for validate_tool — idiomatic TypeScript */
358
+ exports.validateTool = validate_tool;
@@ -215,3 +215,20 @@ export declare class MissingEnvVarError extends Error {
215
215
  readonly docsSlug: string;
216
216
  constructor(toolId: string, envVar: string, docsSlug: string);
217
217
  }
218
+ /**
219
+ * Error thrown when an agent exceeds its budget/cost limit.
220
+ * Mirrors Python SDK: BudgetExceededError(agent_name, total_cost, max_budget)
221
+ *
222
+ * Usage:
223
+ * try { await agent.start("..."); }
224
+ * catch (e) {
225
+ * if (e instanceof BudgetExceededError)
226
+ * console.log(`Agent '${e.agentName}' spent $${e.totalCost} of $${e.maxBudget}`);
227
+ * }
228
+ */
229
+ export declare class BudgetExceededError extends Error {
230
+ readonly agentName: string;
231
+ readonly totalCost: number;
232
+ readonly maxBudget: number;
233
+ constructor(agentName: string, totalCost: number, maxBudget: number);
234
+ }
@@ -5,7 +5,7 @@
5
5
  * Standard interfaces for tool registration, execution, and middleware.
6
6
  */
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.MissingEnvVarError = exports.MissingDependencyError = void 0;
8
+ exports.BudgetExceededError = exports.MissingEnvVarError = exports.MissingDependencyError = void 0;
9
9
  /**
10
10
  * Error thrown when optional dependency is missing
11
11
  */
@@ -47,3 +47,24 @@ class MissingEnvVarError extends Error {
47
47
  }
48
48
  }
49
49
  exports.MissingEnvVarError = MissingEnvVarError;
50
+ /**
51
+ * Error thrown when an agent exceeds its budget/cost limit.
52
+ * Mirrors Python SDK: BudgetExceededError(agent_name, total_cost, max_budget)
53
+ *
54
+ * Usage:
55
+ * try { await agent.start("..."); }
56
+ * catch (e) {
57
+ * if (e instanceof BudgetExceededError)
58
+ * console.log(`Agent '${e.agentName}' spent $${e.totalCost} of $${e.maxBudget}`);
59
+ * }
60
+ */
61
+ class BudgetExceededError extends Error {
62
+ constructor(agentName, totalCost, maxBudget) {
63
+ super(`Agent '${agentName}' exceeded budget: $${totalCost.toFixed(4)} >= $${maxBudget.toFixed(4)}`);
64
+ this.agentName = agentName;
65
+ this.totalCost = totalCost;
66
+ this.maxBudget = maxBudget;
67
+ this.name = 'BudgetExceededError';
68
+ }
69
+ }
70
+ exports.BudgetExceededError = BudgetExceededError;
@@ -250,22 +250,52 @@ async function scrapeUrl(url) {
250
250
  // ============================================================================
251
251
  // UTILITY TOOLS
252
252
  // ============================================================================
253
+ /** Shell metacharacters that enable command chaining or substitution */
254
+ const SHELL_METACHAR_PATTERN = /[;|&`><]|\$\([^)]*\)|\$\{/;
255
+ function containsShellMetacharacters(command) {
256
+ return SHELL_METACHAR_PATTERN.test(command);
257
+ }
258
+ function parseCommandParts(command) {
259
+ const parts = command.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) ?? [];
260
+ return parts.map((part) => part.replace(/^["']|["']$/g, ''));
261
+ }
253
262
  /**
254
263
  * Execute shell command (safe version - read-only commands)
255
264
  */
256
265
  async function shell(command) {
257
- // Only allow safe read-only commands
258
266
  const safeCommands = ['ls', 'cat', 'head', 'tail', 'wc', 'grep', 'find', 'echo', 'date', 'pwd', 'which'];
259
- const firstWord = command.split(/\s+/)[0];
260
- if (!safeCommands.includes(firstWord)) {
261
- return { success: false, error: `Command not allowed: ${firstWord}` };
267
+ const trimmed = command.trim();
268
+ if (!trimmed) {
269
+ return { success: false, error: 'Empty command' };
270
+ }
271
+ if (containsShellMetacharacters(trimmed)) {
272
+ return { success: false, error: 'Shell metacharacters are not allowed' };
273
+ }
274
+ const parts = parseCommandParts(trimmed);
275
+ const cmd = parts[0];
276
+ if (!safeCommands.includes(cmd)) {
277
+ return { success: false, error: `Command not allowed: ${cmd}` };
262
278
  }
263
279
  try {
264
- const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
265
- const { promisify } = await Promise.resolve().then(() => __importStar(require('util')));
266
- const execAsync = promisify(exec);
267
- const { stdout, stderr } = await execAsync(command, { timeout: 5000 });
268
- return { success: true, data: stdout || stderr };
280
+ const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
281
+ const result = await new Promise((resolve, reject) => {
282
+ const proc = spawn(cmd, parts.slice(1), {
283
+ shell: false,
284
+ timeout: 5000,
285
+ });
286
+ let stdout = '';
287
+ let stderr = '';
288
+ proc.stdout?.on('data', (data) => { stdout += data.toString(); });
289
+ proc.stderr?.on('data', (data) => { stderr += data.toString(); });
290
+ proc.on('close', (code) => {
291
+ resolve({ stdout, stderr, code: code ?? 1 });
292
+ });
293
+ proc.on('error', reject);
294
+ });
295
+ if (result.code !== 0) {
296
+ return { success: false, error: result.stderr || `Exit code ${result.code}` };
297
+ }
298
+ return { success: true, data: result.stdout || result.stderr };
269
299
  }
270
300
  catch (error) {
271
301
  return { success: false, error: error.message ?? String(error) };
@@ -41,7 +41,10 @@ export declare function createWorkflowFromYAML(definition: YAMLWorkflowDefinitio
41
41
  /**
42
42
  * Load workflow from YAML file
43
43
  */
44
- export declare function loadWorkflowFromFile(filePath: string, agents?: Record<string, any>, tools?: Record<string, any>): Promise<ParsedWorkflow>;
44
+ export declare function loadWorkflowFromFile(filePath: string, agents?: Record<string, any>, tools?: Record<string, any>, options?: {
45
+ basePath?: string;
46
+ maxFileSizeBytes?: number;
47
+ }): Promise<ParsedWorkflow>;
45
48
  /**
46
49
  * Validate YAML workflow definition
47
50
  */