dank-ai 1.0.31 → 1.0.33

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/lib/agent.js CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  const Joi = require('joi');
9
- const { DEFAULT_CONFIG, SUPPORTED_LLMS, DOCKER_CONFIG } = require('./constants');
9
+ const { DEFAULT_CONFIG, SUPPORTED_LLMS, DOCKER_CONFIG, INSTANCE_TYPES } = require('./constants');
10
10
  const { ToolRegistry, ToolExecutor } = require('./tools');
11
11
  const builtinTools = require('./tools/builtin');
12
12
 
@@ -28,6 +28,11 @@ class DankAgent {
28
28
  if (config.enableBuiltinTools !== false) {
29
29
  this.registerBuiltinTools();
30
30
  }
31
+
32
+ // Ensure instanceType has a default value if not set
33
+ if (!this.config.instanceType) {
34
+ this.config.instanceType = 'small';
35
+ }
31
36
  }
32
37
 
33
38
  /**
@@ -59,24 +64,59 @@ class DankAgent {
59
64
  }
60
65
 
61
66
  /**
62
- * Set resource limits for the container
67
+ * Set instance type (small, medium, large, xlarge)
68
+ * @param {string} instanceType - Instance type string
63
69
  */
64
- setResources(resources) {
65
- const schema = Joi.object({
66
- memory: Joi.string().pattern(/^\d+[mMgG]$/).default('512m'),
67
- cpu: Joi.number().min(0.1).max(8).default(1),
68
- timeout: Joi.number().min(1000).default(30000)
69
- });
70
+ setInstanceType(instanceType) {
71
+ if (!instanceType || typeof instanceType !== 'string') {
72
+ throw new Error('Instance type must be a non-empty string');
73
+ }
70
74
 
71
- const { error, value } = schema.validate(resources);
72
- if (error) {
73
- throw new Error(`Invalid resource configuration: ${error.message}`);
75
+ const normalizedType = instanceType.toLowerCase().trim();
76
+
77
+ if (!INSTANCE_TYPES[normalizedType]) {
78
+ const validTypes = Object.keys(INSTANCE_TYPES).join(', ');
79
+ throw new Error(`Invalid instance type: "${instanceType}". Valid types are: ${validTypes}`);
74
80
  }
75
81
 
76
- this.config.resources = { ...this.config.resources, ...value };
82
+ this.config.instanceType = normalizedType;
77
83
  return this;
78
84
  }
79
85
 
86
+ /**
87
+ * @deprecated Use setInstanceType() instead. This method is kept for backward compatibility.
88
+ * Set resource limits for the container
89
+ */
90
+ setResources(resources) {
91
+ // Map old resources format to instance type
92
+ if (resources && typeof resources === 'object') {
93
+ const memory = resources.memory || '512m';
94
+ const cpu = resources.cpu || 1;
95
+
96
+ // Try to map to an instance type
97
+ let instanceType = 'small'; // default
98
+
99
+ if (memory === '512m' && cpu === 1) {
100
+ instanceType = 'small';
101
+ } else if (memory === '1g' && cpu === 2) {
102
+ instanceType = 'medium';
103
+ } else if (memory === '2g' && cpu === 2) {
104
+ instanceType = 'large';
105
+ } else if (memory === '4g' && cpu === 4) {
106
+ instanceType = 'xlarge';
107
+ } else {
108
+ // For custom configurations, default to small and log a warning
109
+ console.warn(`⚠️ setResources() is deprecated. Using 'small' instance type. Please use setInstanceType('small'|'medium'|'large'|'xlarge') instead.`);
110
+ instanceType = 'small';
111
+ }
112
+
113
+ return this.setInstanceType(instanceType);
114
+ }
115
+
116
+ // If no resources provided, default to small
117
+ return this.setInstanceType('small');
118
+ }
119
+
80
120
  /**
81
121
  * Set Docker configuration including base image
82
122
  */
@@ -116,7 +156,6 @@ class DankAgent {
116
156
  */
117
157
  setPromptingServer(options = {}) {
118
158
  const schema = Joi.object({
119
- protocol: Joi.string().valid('websocket', 'tcp', 'http').default('http'),
120
159
  port: Joi.number().min(1000).max(65535).default(3000),
121
160
  authentication: Joi.boolean().default(false),
122
161
  maxConnections: Joi.number().min(1).max(1000).default(50),
@@ -131,12 +170,13 @@ class DankAgent {
131
170
  // Set the port in docker config
132
171
  this.config.docker = { ...this.config.docker, port: value.port };
133
172
 
134
- // Set the communication config (excluding port)
173
+ // Set the communication config (always HTTP, excluding port)
135
174
  const { port, ...communicationConfig } = value;
136
175
  this.config.communication = {
137
176
  ...this.config.communication,
138
177
  directPrompting: {
139
178
  enabled: true,
179
+ protocol: 'http', // Always HTTP
140
180
  ...communicationConfig
141
181
  }
142
182
  };
@@ -162,6 +202,8 @@ class DankAgent {
162
202
 
163
203
  /**
164
204
  * Enable HTTP server with Express.js
205
+ * Optional: Use this to configure HTTP options (port, CORS, rate limiting, etc.)
206
+ * HTTP auto-enables when routes are added, so this is only needed for custom configuration
165
207
  */
166
208
  enableHttp(options = {}) {
167
209
  const schema = Joi.object({
@@ -186,11 +228,15 @@ class DankAgent {
186
228
  throw new Error(`Invalid HTTP configuration: ${error.message}`);
187
229
  }
188
230
 
231
+ // Preserve existing routes and middleware if HTTP was already auto-enabled
232
+ const existingRoutes = this.config.http?.routes || new Map();
233
+ const existingMiddleware = this.config.http?.middleware || [];
234
+
189
235
  this.config.http = {
190
236
  enabled: true,
191
237
  ...value,
192
- routes: new Map(),
193
- middleware: []
238
+ routes: existingRoutes,
239
+ middleware: existingMiddleware
194
240
  };
195
241
 
196
242
  return this;
@@ -198,10 +244,24 @@ class DankAgent {
198
244
 
199
245
  /**
200
246
  * Add HTTP route handler
247
+ * Auto-enables HTTP server if not already enabled
201
248
  */
202
249
  addRoute(method, path, handler, options = {}) {
250
+ // Auto-enable HTTP if not already enabled
203
251
  if (!this.config.http || !this.config.http.enabled) {
204
- throw new Error('HTTP server must be enabled before adding routes. Call enableHttp() first.');
252
+ this.config.http = {
253
+ enabled: true,
254
+ port: 3000,
255
+ host: '0.0.0.0',
256
+ cors: true,
257
+ rateLimit: {
258
+ windowMs: 15 * 60 * 1000,
259
+ max: 100,
260
+ message: 'Too many requests'
261
+ },
262
+ routes: new Map(),
263
+ middleware: []
264
+ };
205
265
  }
206
266
 
207
267
  if (typeof handler !== 'function') {
@@ -215,6 +275,11 @@ class DankAgent {
215
275
  throw new Error(`Invalid HTTP method: ${method}. Valid methods: ${validMethods.join(', ')}`);
216
276
  }
217
277
 
278
+ // Ensure routes Map exists
279
+ if (!this.config.http.routes) {
280
+ this.config.http.routes = new Map();
281
+ }
282
+
218
283
  const routeKey = `${upperMethod}:${path}`;
219
284
 
220
285
  if (!this.config.http.routes.has(routeKey)) {
@@ -239,10 +304,24 @@ class DankAgent {
239
304
 
240
305
  /**
241
306
  * Add HTTP middleware
307
+ * Auto-enables HTTP server if not already enabled
242
308
  */
243
309
  addMiddleware(middleware, options = {}) {
310
+ // Auto-enable HTTP if not already enabled
244
311
  if (!this.config.http || !this.config.http.enabled) {
245
- throw new Error('HTTP server must be enabled before adding middleware. Call enableHttp() first.');
312
+ this.config.http = {
313
+ enabled: true,
314
+ port: 3000,
315
+ host: '0.0.0.0',
316
+ cors: true,
317
+ rateLimit: {
318
+ windowMs: 15 * 60 * 1000,
319
+ max: 100,
320
+ message: 'Too many requests'
321
+ },
322
+ routes: new Map(),
323
+ middleware: []
324
+ };
246
325
  }
247
326
 
248
327
  if (typeof middleware !== 'function') {
@@ -434,7 +513,7 @@ class DankAgent {
434
513
  ...this.config.communication,
435
514
  directPrompting: {
436
515
  enabled: finalEnabled,
437
- protocol: currentDirectPrompting?.protocol || 'websocket',
516
+ protocol: 'http', // Always HTTP
438
517
  authentication: currentDirectPrompting?.authentication || false,
439
518
  maxConnections: currentDirectPrompting?.maxConnections || 100,
440
519
  timeout: currentDirectPrompting?.timeout || 30000
@@ -570,11 +649,7 @@ class DankAgent {
570
649
 
571
650
  prompt: Joi.string().optional(),
572
651
 
573
- resources: Joi.object({
574
- memory: Joi.string().pattern(/^\d+[mMgG]$/).default('512m'),
575
- cpu: Joi.number().min(0.1).max(8).default(1),
576
- timeout: Joi.number().min(1000).default(30000)
577
- }).default({}),
652
+ instanceType: Joi.string().valid('small', 'medium', 'large', 'xlarge').default('small'),
578
653
 
579
654
  docker: Joi.object({
580
655
  baseImage: Joi.string().default(`${DOCKER_CONFIG.baseImagePrefix}:${DOCKER_CONFIG.defaultTag}`),
@@ -584,7 +659,7 @@ class DankAgent {
584
659
  communication: Joi.object({
585
660
  directPrompting: Joi.object({
586
661
  enabled: Joi.boolean().default(false),
587
- protocol: Joi.string().valid('websocket', 'tcp', 'http').default('http'),
662
+ protocol: Joi.string().valid('http').default('http'), // Always HTTP, kept for backward compatibility
588
663
  authentication: Joi.boolean().default(false),
589
664
  maxConnections: Joi.number().min(1).max(1000).default(50),
590
665
  timeout: Joi.number().min(1000).default(30000)
package/lib/cli/init.js CHANGED
@@ -320,20 +320,7 @@ Handle LLM interactions and modify prompts/responses:
320
320
  })
321
321
  \`\`\`
322
322
 
323
- ### 2. HTTP API Events (\`tool:http-server\`)
324
- Handle HTTP requests and responses:
325
-
326
- \`\`\`javascript
327
- .addHandler('tool:http-server:call', (data) => {
328
- console.log('HTTP request received:', data.method, data.path);
329
- })
330
-
331
- .addHandler('tool:http-server:response', (data) => {
332
- console.log('HTTP response sent:', data.statusCode);
333
- })
334
- \`\`\`
335
-
336
- ### 3. System Events
323
+ ### 2. System Events
337
324
  Handle agent lifecycle and errors:
338
325
 
339
326
  \`\`\`javascript
@@ -14,7 +14,6 @@ const analytics = require('../analytics');
14
14
  function extractAgentMetadata(agent, buildOptions, imageName) {
15
15
  const config = agent.config || {};
16
16
  const dockerConfig = config.docker || {};
17
- const resources = config.resources || {};
18
17
  const communication = config.communication || {};
19
18
  const directPrompting = communication.directPrompting || {};
20
19
  const httpConfig = config.http || {};
@@ -39,12 +38,10 @@ function extractAgentMetadata(agent, buildOptions, imageName) {
39
38
  timeout: directPrompting.timeout || 30000
40
39
  } : null;
41
40
 
42
- // Extract resources configuration
43
- const resourcesConfig = {
44
- memory: resources.memory || '512m',
45
- cpu: resources.cpu || 1,
46
- timeout: resources.timeout || 30000
47
- };
41
+ // Extract resources configuration from instance type
42
+ const { AgentConfig } = require('../config');
43
+ const instanceType = config.instanceType || 'small';
44
+ const resourcesConfig = AgentConfig.getResourcesFromInstanceType(instanceType);
48
45
 
49
46
  // Extract HTTP server configuration if enabled
50
47
  const httpServer = httpConfig.enabled ? {
@@ -159,7 +156,8 @@ async function productionBuildCommand(options) {
159
156
  namespace: options.namespace || agentImageConfig.namespace,
160
157
  tagByAgent: Boolean(options.tagByAgent || agentImageConfig.tagByAgent),
161
158
  force: options.force || false,
162
- push: options.push || false
159
+ push: options.push || false,
160
+ baseImageOverride: options.baseImageOverride || null
163
161
  };
164
162
 
165
163
  const result = await dockerManager.buildProductionImage(agent, buildOptions);
package/lib/config.js CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  const Joi = require('joi');
6
- const { SUPPORTED_LLMS } = require('./constants');
6
+ const { SUPPORTED_LLMS, INSTANCE_TYPES } = require('./constants');
7
7
 
8
8
  class AgentConfig {
9
9
  /**
@@ -76,28 +76,22 @@ class AgentConfig {
76
76
  }
77
77
 
78
78
  /**
79
- * Validate resource configuration
79
+ * Get resources (memory, cpu) from instance type
80
+ * @param {string} instanceType - Instance type (small, medium, large, xlarge)
81
+ * @returns {Object} Resources object with memory and cpu
80
82
  */
81
- static validateResources(resources) {
82
- const schema = Joi.object({
83
- memory: Joi.string()
84
- .pattern(/^\d+[mMgG]$/)
85
- .default('512m')
86
- .messages({
87
- 'string.pattern.base': 'Memory must be in format like "512m" or "1g"'
88
- }),
89
- cpu: Joi.number().min(0.1).max(32).default(1),
90
- timeout: Joi.number().min(1000).default(30000),
91
- maxRestarts: Joi.number().min(0).default(3),
92
- healthCheckInterval: Joi.number().min(1000).default(10000)
93
- });
94
-
95
- const { error, value } = schema.validate(resources);
96
- if (error) {
97
- throw new Error(`Invalid resource configuration: ${error.message}`);
83
+ static getResourcesFromInstanceType(instanceType) {
84
+ const normalizedType = (instanceType || 'small').toLowerCase().trim();
85
+ const instanceConfig = INSTANCE_TYPES[normalizedType];
86
+
87
+ if (!instanceConfig) {
88
+ throw new Error(`Invalid instance type: "${instanceType}". Valid types are: ${Object.keys(INSTANCE_TYPES).join(', ')}`);
98
89
  }
99
-
100
- return value;
90
+
91
+ return {
92
+ memory: instanceConfig.memory,
93
+ cpu: instanceConfig.cpu
94
+ };
101
95
  }
102
96
 
103
97
  /**
@@ -143,11 +137,13 @@ class AgentConfig {
143
137
  }
144
138
 
145
139
  // Add HTTP server environment variables
146
- if (agent.config.http && agent.config.http.enabled) {
140
+ // HTTP is enabled if explicitly enabled OR if routes exist (auto-enabled)
141
+ const hasRoutes = agent.config.http?.routes && agent.config.http.routes.size > 0;
142
+ if (agent.config.http && (agent.config.http.enabled || hasRoutes)) {
147
143
  env.HTTP_ENABLED = 'true';
148
- env.HTTP_PORT = agent.config.http.port.toString();
149
- env.HTTP_HOST = agent.config.http.host;
150
- env.HTTP_CORS = agent.config.http.cors.toString();
144
+ env.HTTP_PORT = (agent.config.http.port || 3000).toString();
145
+ env.HTTP_HOST = agent.config.http.host || '0.0.0.0';
146
+ env.HTTP_CORS = (agent.config.http.cors !== false).toString();
151
147
 
152
148
  if (agent.config.http.rateLimit) {
153
149
  env.HTTP_RATE_LIMIT = 'true';
@@ -158,20 +154,23 @@ class AgentConfig {
158
154
  }
159
155
 
160
156
  // Add direct prompting environment variables
157
+ // If setPromptingServer was called, it sets directPrompting.enabled = true
158
+ // The main HTTP server always runs, and /prompt endpoint is available if setPromptingServer was called
161
159
  if (agent.config.communication?.directPrompting?.enabled) {
162
160
  env.DIRECT_PROMPTING_ENABLED = 'true';
163
- env.DIRECT_PROMPTING_PROTOCOL = agent.config.communication.directPrompting.protocol || 'websocket';
164
- env.DIRECT_PROMPTING_MAX_CONNECTIONS = agent.config.communication.directPrompting.maxConnections?.toString() || '100';
165
- env.DIRECT_PROMPTING_AUTHENTICATION = agent.config.communication.directPrompting.authentication?.toString() || 'false';
166
- env.DIRECT_PROMPTING_TIMEOUT = agent.config.communication.directPrompting.timeout?.toString() || '30000';
161
+ env.DIRECT_PROMPTING_PROTOCOL = 'http'; // Always HTTP
162
+ env.DIRECT_PROMPTING_MAX_CONNECTIONS = agent.config.communication.directPrompting?.maxConnections?.toString() || '100';
163
+ env.DIRECT_PROMPTING_AUTHENTICATION = agent.config.communication.directPrompting?.authentication?.toString() || 'false';
164
+ env.DIRECT_PROMPTING_TIMEOUT = agent.config.communication.directPrompting?.timeout?.toString() || '30000';
167
165
  } else {
168
166
  env.DIRECT_PROMPTING_ENABLED = 'false';
169
167
  }
170
168
 
171
- // Add main Docker port
172
- if (agent.config.docker?.port) {
173
- env.DOCKER_PORT = agent.config.docker.port.toString();
174
- }
169
+ // Add main Docker port (always set, defaults to 3000 if not specified)
170
+ const dockerPort = agent.config.docker?.port || 3000;
171
+ env.DOCKER_PORT = dockerPort.toString();
172
+ // Health check uses the same port as the main agent port
173
+ env.HEALTH_PORT = dockerPort.toString();
175
174
 
176
175
  return env;
177
176
  }
package/lib/constants.js CHANGED
@@ -19,15 +19,31 @@ const DEFAULT_CONFIG = {
19
19
  maxTokens: 1000
20
20
  },
21
21
  prompt: 'You are a helpful AI assistant.',
22
- resources: {
23
- memory: '512m',
24
- cpu: 1,
25
- timeout: 30000
26
- },
22
+ instanceType: 'small',
27
23
  environment: {},
28
24
  custom: {}
29
25
  };
30
26
 
27
+ // Instance type mappings: instanceType -> { memory, cpu }
28
+ const INSTANCE_TYPES = {
29
+ small: {
30
+ memory: '512m',
31
+ cpu: 1
32
+ },
33
+ medium: {
34
+ memory: '1g',
35
+ cpu: 2
36
+ },
37
+ large: {
38
+ memory: '2g',
39
+ cpu: 2
40
+ },
41
+ xlarge: {
42
+ memory: '4g',
43
+ cpu: 4
44
+ }
45
+ };
46
+
31
47
  const DOCKER_CONFIG = {
32
48
  baseImage: 'deltadarkly/dank-agent-base',
33
49
  baseImagePrefix: 'deltadarkly/dank-agent-base',
@@ -54,5 +70,6 @@ module.exports = {
54
70
  SUPPORTED_LLMS,
55
71
  DEFAULT_CONFIG,
56
72
  DOCKER_CONFIG,
57
- AGENT_EVENTS
73
+ AGENT_EVENTS,
74
+ INSTANCE_TYPES
58
75
  };