dank-ai 1.0.32 → 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/README.md +49 -50
- package/bin/dank +1 -0
- package/docker/entrypoint.js +140 -353
- package/lib/agent.js +100 -25
- package/lib/cli/init.js +1 -14
- package/lib/cli/production-build.js +6 -8
- package/lib/config.js +32 -33
- package/lib/constants.js +23 -6
- package/lib/docker/manager.js +135 -26
- package/lib/project.js +1 -4
- package/package.json +1 -1
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
|
|
67
|
+
* Set instance type (small, medium, large, xlarge)
|
|
68
|
+
* @param {string} instanceType - Instance type string
|
|
63
69
|
*/
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
|
72
|
-
|
|
73
|
-
|
|
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.
|
|
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:
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
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('
|
|
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.
|
|
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
|
|
44
|
-
|
|
45
|
-
|
|
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
|
-
*
|
|
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
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
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
|
|
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
|
|
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 =
|
|
164
|
-
env.DIRECT_PROMPTING_MAX_CONNECTIONS = agent.config.communication.directPrompting
|
|
165
|
-
env.DIRECT_PROMPTING_AUTHENTICATION = agent.config.communication.directPrompting
|
|
166
|
-
env.DIRECT_PROMPTING_TIMEOUT = agent.config.communication.directPrompting
|
|
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
|
-
|
|
173
|
-
|
|
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
|
-
|
|
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
|
};
|