cipher-security 2.0.0
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/bin/cipher.js +566 -0
- package/lib/api/billing.js +321 -0
- package/lib/api/compliance.js +693 -0
- package/lib/api/controls.js +1401 -0
- package/lib/api/index.js +49 -0
- package/lib/api/marketplace.js +467 -0
- package/lib/api/openai-proxy.js +383 -0
- package/lib/api/server.js +685 -0
- package/lib/autonomous/feedback-loop.js +554 -0
- package/lib/autonomous/framework.js +512 -0
- package/lib/autonomous/index.js +97 -0
- package/lib/autonomous/leaderboard.js +594 -0
- package/lib/autonomous/modes/architect.js +412 -0
- package/lib/autonomous/modes/blue.js +386 -0
- package/lib/autonomous/modes/incident.js +684 -0
- package/lib/autonomous/modes/privacy.js +369 -0
- package/lib/autonomous/modes/purple.js +294 -0
- package/lib/autonomous/modes/recon.js +250 -0
- package/lib/autonomous/parallel.js +587 -0
- package/lib/autonomous/researcher.js +583 -0
- package/lib/autonomous/runner.js +955 -0
- package/lib/autonomous/scheduler.js +615 -0
- package/lib/autonomous/task-parser.js +127 -0
- package/lib/autonomous/validators/forensic.js +266 -0
- package/lib/autonomous/validators/osint.js +216 -0
- package/lib/autonomous/validators/privacy.js +296 -0
- package/lib/autonomous/validators/purple.js +298 -0
- package/lib/autonomous/validators/sigma.js +248 -0
- package/lib/autonomous/validators/threat-model.js +363 -0
- package/lib/benchmark/agent.js +119 -0
- package/lib/benchmark/baselines.js +43 -0
- package/lib/benchmark/builder.js +143 -0
- package/lib/benchmark/config.js +35 -0
- package/lib/benchmark/coordinator.js +91 -0
- package/lib/benchmark/index.js +20 -0
- package/lib/benchmark/llm.js +58 -0
- package/lib/benchmark/models.js +137 -0
- package/lib/benchmark/reporter.js +103 -0
- package/lib/benchmark/runner.js +103 -0
- package/lib/benchmark/sandbox.js +96 -0
- package/lib/benchmark/scorer.js +32 -0
- package/lib/benchmark/solver.js +166 -0
- package/lib/benchmark/tools.js +62 -0
- package/lib/bot/bot.js +238 -0
- package/lib/brand.js +105 -0
- package/lib/commands.js +100 -0
- package/lib/complexity.js +377 -0
- package/lib/config.js +213 -0
- package/lib/gateway/client.js +309 -0
- package/lib/gateway/commands.js +991 -0
- package/lib/gateway/config-validate.js +109 -0
- package/lib/gateway/gateway.js +367 -0
- package/lib/gateway/index.js +62 -0
- package/lib/gateway/mode.js +309 -0
- package/lib/gateway/plugins.js +222 -0
- package/lib/gateway/prompt.js +214 -0
- package/lib/mcp/server.js +262 -0
- package/lib/memory/compressor.js +425 -0
- package/lib/memory/engine.js +763 -0
- package/lib/memory/evolution.js +668 -0
- package/lib/memory/index.js +58 -0
- package/lib/memory/orchestrator.js +506 -0
- package/lib/memory/retriever.js +515 -0
- package/lib/memory/synthesizer.js +333 -0
- package/lib/pipeline/async-scanner.js +510 -0
- package/lib/pipeline/binary-analysis.js +1043 -0
- package/lib/pipeline/dom-xss-scanner.js +435 -0
- package/lib/pipeline/github-actions.js +792 -0
- package/lib/pipeline/index.js +124 -0
- package/lib/pipeline/osint.js +498 -0
- package/lib/pipeline/sarif.js +373 -0
- package/lib/pipeline/scanner.js +880 -0
- package/lib/pipeline/template-manager.js +525 -0
- package/lib/pipeline/xss-scanner.js +353 -0
- package/lib/setup-wizard.js +288 -0
- package/package.json +31 -0
|
@@ -0,0 +1,512 @@
|
|
|
1
|
+
// Copyright (c) 2026 defconxt. All rights reserved.
|
|
2
|
+
// Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
3
|
+
// CIPHER is a trademark of defconxt.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* framework.js — Mode-agnostic agent framework for CIPHER autonomous operations.
|
|
7
|
+
*
|
|
8
|
+
* Ported from autonomous/framework.py. Foundation types for the multi-mode agent system:
|
|
9
|
+
* - truncateOutput: standalone output truncation utility
|
|
10
|
+
* - ValidationResult: output validation with errors, warnings, and scoring
|
|
11
|
+
* - ModeAgentResult: structured result from agent execution
|
|
12
|
+
* - ToolRegistry: register and dispatch tools with flexible context
|
|
13
|
+
* - NullValidator: pass-through validator for modes without validation
|
|
14
|
+
* - ModeAgentConfig: configuration for a mode-specific agent
|
|
15
|
+
* - BaseAgent: generalized tool-use loop (extracted from SecurityAgent)
|
|
16
|
+
*
|
|
17
|
+
* All exports are named ESM exports. All imports lazy where needed.
|
|
18
|
+
*
|
|
19
|
+
* @module autonomous/framework
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
const debug = process.env.CIPHER_DEBUG === '1'
|
|
23
|
+
? (/** @type {string} */ msg) => process.stderr.write(`[autonomous] ${msg}\n`)
|
|
24
|
+
: () => {};
|
|
25
|
+
|
|
26
|
+
// Maximum tool output length to prevent context window bloat
|
|
27
|
+
const MAX_OUTPUT_CHARS = 4000;
|
|
28
|
+
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// Standalone utilities
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Truncate tool output to prevent context window bloat.
|
|
35
|
+
*
|
|
36
|
+
* @param {string} output
|
|
37
|
+
* @param {number} [maxChars=4000]
|
|
38
|
+
* @returns {string}
|
|
39
|
+
*/
|
|
40
|
+
export function truncateOutput(output, maxChars = MAX_OUTPUT_CHARS) {
|
|
41
|
+
if (output.length <= maxChars) return output;
|
|
42
|
+
return output.slice(0, maxChars) + `\n... [truncated, ${output.length} chars total]`;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// ---------------------------------------------------------------------------
|
|
46
|
+
// Result classes
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Outcome of validating a mode agent's result.
|
|
51
|
+
*/
|
|
52
|
+
export class ValidationResult {
|
|
53
|
+
/**
|
|
54
|
+
* @param {Object} opts
|
|
55
|
+
* @param {boolean} opts.valid
|
|
56
|
+
* @param {string[]} opts.errors
|
|
57
|
+
* @param {string[]} opts.warnings
|
|
58
|
+
* @param {number} [opts.score=1.0]
|
|
59
|
+
* @param {Object} [opts.metadata={}]
|
|
60
|
+
*/
|
|
61
|
+
constructor({ valid, errors, warnings, score = 1.0, metadata = {} }) {
|
|
62
|
+
this.valid = valid;
|
|
63
|
+
this.errors = errors;
|
|
64
|
+
this.warnings = warnings;
|
|
65
|
+
this.score = score;
|
|
66
|
+
this.metadata = metadata;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Structured result from a mode agent execution.
|
|
72
|
+
*/
|
|
73
|
+
export class ModeAgentResult {
|
|
74
|
+
/**
|
|
75
|
+
* @param {Object} opts
|
|
76
|
+
* @param {string} opts.mode
|
|
77
|
+
* @param {Object} [opts.outputData={}]
|
|
78
|
+
* @param {string} [opts.outputText='']
|
|
79
|
+
* @param {string[]} [opts.steps=[]]
|
|
80
|
+
* @param {number} [opts.tokensIn=0]
|
|
81
|
+
* @param {number} [opts.tokensOut=0]
|
|
82
|
+
* @param {number} [opts.toolCalls=0]
|
|
83
|
+
* @param {number} [opts.turnsUsed=0]
|
|
84
|
+
* @param {ValidationResult|null} [opts.validation=null]
|
|
85
|
+
* @param {string|null} [opts.error=null]
|
|
86
|
+
* @param {number} [opts.durationS=0]
|
|
87
|
+
*/
|
|
88
|
+
constructor({
|
|
89
|
+
mode,
|
|
90
|
+
outputData = {},
|
|
91
|
+
outputText = '',
|
|
92
|
+
steps = [],
|
|
93
|
+
tokensIn = 0,
|
|
94
|
+
tokensOut = 0,
|
|
95
|
+
toolCalls = 0,
|
|
96
|
+
turnsUsed = 0,
|
|
97
|
+
validation = null,
|
|
98
|
+
error = null,
|
|
99
|
+
durationS = 0,
|
|
100
|
+
}) {
|
|
101
|
+
this.mode = mode;
|
|
102
|
+
this.outputData = outputData;
|
|
103
|
+
this.outputText = outputText;
|
|
104
|
+
this.steps = steps;
|
|
105
|
+
this.tokensIn = tokensIn;
|
|
106
|
+
this.tokensOut = tokensOut;
|
|
107
|
+
this.toolCalls = toolCalls;
|
|
108
|
+
this.turnsUsed = turnsUsed;
|
|
109
|
+
this.validation = validation;
|
|
110
|
+
this.error = error;
|
|
111
|
+
this.durationS = durationS;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
// ToolRegistry
|
|
117
|
+
// ---------------------------------------------------------------------------
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Registry for tool schemas and dispatch handlers.
|
|
121
|
+
*
|
|
122
|
+
* Tools are registered with an Anthropic-format schema and a handler callable.
|
|
123
|
+
* The handler signature is (context, input) => string.
|
|
124
|
+
*/
|
|
125
|
+
export class ToolRegistry {
|
|
126
|
+
constructor() {
|
|
127
|
+
/** @type {Array<Object>} */
|
|
128
|
+
this._schemas = [];
|
|
129
|
+
/** @type {Map<string, Function>} */
|
|
130
|
+
this._dispatch = new Map();
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Register a tool with its schema and handler.
|
|
135
|
+
*
|
|
136
|
+
* @param {string} name - Unique tool name
|
|
137
|
+
* @param {Object} schema - Anthropic-format tool schema dict
|
|
138
|
+
* @param {Function} handler - (context, input) => string
|
|
139
|
+
* @throws {Error} If a tool with this name is already registered
|
|
140
|
+
*/
|
|
141
|
+
register(name, schema, handler) {
|
|
142
|
+
if (this._dispatch.has(name)) {
|
|
143
|
+
const registered = [...this._dispatch.keys()].sort().join(', ');
|
|
144
|
+
throw new Error(
|
|
145
|
+
`Tool already registered: '${name}'. Registered tools: ${registered}`
|
|
146
|
+
);
|
|
147
|
+
}
|
|
148
|
+
this._schemas.push(schema);
|
|
149
|
+
this._dispatch.set(name, handler);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Return a copy of all registered tool schemas.
|
|
154
|
+
* @returns {Array<Object>}
|
|
155
|
+
*/
|
|
156
|
+
getSchemas() {
|
|
157
|
+
return [...this._schemas];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Dispatch a tool call to its handler.
|
|
162
|
+
*
|
|
163
|
+
* @param {string} name - Tool name from the LLM's tool_use block
|
|
164
|
+
* @param {Object} toolInput - Tool input parameters from the LLM
|
|
165
|
+
* @param {*} [context=null] - Arbitrary context passed to the handler
|
|
166
|
+
* @returns {string} Tool output string, truncated to MAX_OUTPUT_CHARS
|
|
167
|
+
* @throws {Error} If tool name is not recognized
|
|
168
|
+
*/
|
|
169
|
+
dispatch(name, toolInput, context = null) {
|
|
170
|
+
const handler = this._dispatch.get(name);
|
|
171
|
+
if (!handler) {
|
|
172
|
+
const available = [...this._dispatch.keys()].sort().join(', ');
|
|
173
|
+
throw new Error(`Unknown tool: '${name}'. Available: ${available}`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
let result;
|
|
177
|
+
try {
|
|
178
|
+
result = handler(context, toolInput);
|
|
179
|
+
} catch (e) {
|
|
180
|
+
result = `TOOL ERROR: ${e.constructor.name}: ${e.message}`;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return truncateOutput(String(result));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Check if a tool is registered.
|
|
188
|
+
* @param {string} name
|
|
189
|
+
* @returns {boolean}
|
|
190
|
+
*/
|
|
191
|
+
hasTool(name) {
|
|
192
|
+
return this._dispatch.has(name);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Return list of registered tool names.
|
|
197
|
+
* @returns {string[]}
|
|
198
|
+
*/
|
|
199
|
+
toolNames() {
|
|
200
|
+
return [...this._dispatch.keys()];
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
// Validator protocol (duck-type: any object with validate(result) method)
|
|
206
|
+
// NullValidator — pass-through validator
|
|
207
|
+
// ---------------------------------------------------------------------------
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Pass-through validator that always returns valid.
|
|
211
|
+
* Used for modes that don't need output validation.
|
|
212
|
+
*/
|
|
213
|
+
export class NullValidator {
|
|
214
|
+
/**
|
|
215
|
+
* @param {ModeAgentResult} _result
|
|
216
|
+
* @returns {ValidationResult}
|
|
217
|
+
*/
|
|
218
|
+
validate(_result) {
|
|
219
|
+
return new ValidationResult({ valid: true, errors: [], warnings: [], score: 1.0 });
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// ---------------------------------------------------------------------------
|
|
224
|
+
// Mode configuration
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Configuration for a mode-specific agent.
|
|
229
|
+
*/
|
|
230
|
+
export class ModeAgentConfig {
|
|
231
|
+
/**
|
|
232
|
+
* @param {Object} opts
|
|
233
|
+
* @param {string} opts.mode
|
|
234
|
+
* @param {ToolRegistry} opts.toolRegistry
|
|
235
|
+
* @param {string} opts.systemPromptTemplate
|
|
236
|
+
* @param {Object} opts.validator - Any object with validate(result) method
|
|
237
|
+
* @param {number} [opts.maxTurns=30]
|
|
238
|
+
* @param {number} [opts.maxTokensPerTurn=4096]
|
|
239
|
+
* @param {string} [opts.outputFormat='json']
|
|
240
|
+
* @param {boolean} [opts.requiresSandbox=false]
|
|
241
|
+
* @param {Function|null} [opts.completionCheck=null] - (text: string) => boolean
|
|
242
|
+
* @param {Function|null} [opts.outputParser=null] - (text: string) => Object
|
|
243
|
+
*/
|
|
244
|
+
constructor({
|
|
245
|
+
mode,
|
|
246
|
+
toolRegistry,
|
|
247
|
+
systemPromptTemplate,
|
|
248
|
+
validator,
|
|
249
|
+
maxTurns = 30,
|
|
250
|
+
maxTokensPerTurn = 4096,
|
|
251
|
+
outputFormat = 'json',
|
|
252
|
+
requiresSandbox = false,
|
|
253
|
+
completionCheck = null,
|
|
254
|
+
outputParser = null,
|
|
255
|
+
}) {
|
|
256
|
+
this.mode = mode;
|
|
257
|
+
this.toolRegistry = toolRegistry;
|
|
258
|
+
this.systemPromptTemplate = systemPromptTemplate;
|
|
259
|
+
this.validator = validator;
|
|
260
|
+
this.maxTurns = maxTurns;
|
|
261
|
+
this.maxTokensPerTurn = maxTokensPerTurn;
|
|
262
|
+
this.outputFormat = outputFormat;
|
|
263
|
+
this.requiresSandbox = requiresSandbox;
|
|
264
|
+
this.completionCheck = completionCheck;
|
|
265
|
+
this.outputParser = outputParser;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// ---------------------------------------------------------------------------
|
|
270
|
+
// BaseAgent — generalized tool-use loop
|
|
271
|
+
// ---------------------------------------------------------------------------
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Mode-agnostic LLM agent with pluggable tools, prompts, and validators.
|
|
275
|
+
*
|
|
276
|
+
* Works with any Anthropic-SDK-compatible client (Ollama, Claude, LiteLLM).
|
|
277
|
+
*/
|
|
278
|
+
export class BaseAgent {
|
|
279
|
+
/**
|
|
280
|
+
* @param {Object} opts
|
|
281
|
+
* @param {Object} opts.client - Anthropic-SDK-compatible LLM client
|
|
282
|
+
* @param {string} opts.model - Model name
|
|
283
|
+
* @param {ModeAgentConfig} opts.config - Mode-specific agent configuration
|
|
284
|
+
* @param {*} [opts.context=null] - Arbitrary context passed to tool handlers
|
|
285
|
+
* @param {Function|null} [opts.preToolHook=null] - (toolName, toolInput) => boolean
|
|
286
|
+
*/
|
|
287
|
+
constructor({ client, model, config, context = null, preToolHook = null }) {
|
|
288
|
+
this._client = client;
|
|
289
|
+
this._model = model;
|
|
290
|
+
this._config = config;
|
|
291
|
+
this._context = context;
|
|
292
|
+
this._preToolHook = preToolHook;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Run the agent against a task.
|
|
297
|
+
*
|
|
298
|
+
* Executes a multi-turn tool-use conversation loop:
|
|
299
|
+
* 1. Render system prompt from config template + taskInput
|
|
300
|
+
* 2. Send initial user message
|
|
301
|
+
* 3. Process LLM responses: text blocks → step log, tool_use → dispatch
|
|
302
|
+
* 4. Check completionCheck on every text block and tool output
|
|
303
|
+
* 5. After loop: run outputParser, then validator
|
|
304
|
+
*
|
|
305
|
+
* @param {Object} taskInput - Dict of task parameters
|
|
306
|
+
* @returns {Promise<ModeAgentResult>}
|
|
307
|
+
*/
|
|
308
|
+
async run(taskInput) {
|
|
309
|
+
const result = new ModeAgentResult({ mode: this._config.mode });
|
|
310
|
+
const startTime = performance.now() / 1000;
|
|
311
|
+
|
|
312
|
+
// Render system prompt from template
|
|
313
|
+
let system;
|
|
314
|
+
try {
|
|
315
|
+
system = this._config.systemPromptTemplate.replace(
|
|
316
|
+
/\{(\w+)\}/g,
|
|
317
|
+
(_, key) => {
|
|
318
|
+
if (key in taskInput) return String(taskInput[key]);
|
|
319
|
+
throw new Error(key);
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
} catch (e) {
|
|
323
|
+
result.error = `System prompt template error: missing key '${e.message}'`;
|
|
324
|
+
result.durationS = (performance.now() / 1000) - startTime;
|
|
325
|
+
return result;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Build initial user message
|
|
329
|
+
const userMessage = taskInput.user_message || 'Begin the task.';
|
|
330
|
+
|
|
331
|
+
/** @type {Array<Object>} */
|
|
332
|
+
const messages = [
|
|
333
|
+
{ role: 'user', content: userMessage },
|
|
334
|
+
];
|
|
335
|
+
|
|
336
|
+
const tools = this._config.toolRegistry.getSchemas();
|
|
337
|
+
let completed = false;
|
|
338
|
+
let completedText = '';
|
|
339
|
+
let lastAssistantText = '';
|
|
340
|
+
|
|
341
|
+
// for...else pattern: exhausted flag
|
|
342
|
+
let exhausted = true;
|
|
343
|
+
|
|
344
|
+
for (let turn = 0; turn < this._config.maxTurns; turn++) {
|
|
345
|
+
result.turnsUsed = turn + 1;
|
|
346
|
+
debug(`BaseAgent [${this._config.mode}] turn ${turn + 1}/${this._config.maxTurns}`);
|
|
347
|
+
|
|
348
|
+
let response;
|
|
349
|
+
try {
|
|
350
|
+
response = await this._client.messages.create({
|
|
351
|
+
model: this._model,
|
|
352
|
+
max_tokens: this._config.maxTokensPerTurn,
|
|
353
|
+
system,
|
|
354
|
+
tools,
|
|
355
|
+
messages,
|
|
356
|
+
});
|
|
357
|
+
} catch (e) {
|
|
358
|
+
result.error = `LLM API error: ${e.constructor.name}: ${e.message}`;
|
|
359
|
+
exhausted = false;
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Accumulate token usage
|
|
364
|
+
const usage = response?.usage;
|
|
365
|
+
if (usage) {
|
|
366
|
+
result.tokensIn += usage.input_tokens || 0;
|
|
367
|
+
result.tokensOut += usage.output_tokens || 0;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Process response content blocks
|
|
371
|
+
/** @type {Array<Object>} */
|
|
372
|
+
const toolResults = [];
|
|
373
|
+
/** @type {Array<Object>} */
|
|
374
|
+
const assistantContent = [];
|
|
375
|
+
/** @type {string[]} */
|
|
376
|
+
const turnTextParts = [];
|
|
377
|
+
|
|
378
|
+
for (const block of response.content) {
|
|
379
|
+
if (block.type === 'text') {
|
|
380
|
+
const text = block.text;
|
|
381
|
+
assistantContent.push({ type: 'text', text });
|
|
382
|
+
turnTextParts.push(text);
|
|
383
|
+
result.steps.push(`[think] ${text.slice(0, 200)}`);
|
|
384
|
+
|
|
385
|
+
// Check completion on text
|
|
386
|
+
if (this._config.completionCheck !== null && this._config.completionCheck(text)) {
|
|
387
|
+
completed = true;
|
|
388
|
+
completedText = text;
|
|
389
|
+
}
|
|
390
|
+
} else if (block.type === 'tool_use') {
|
|
391
|
+
const toolName = block.name;
|
|
392
|
+
const toolInput = block.input;
|
|
393
|
+
const toolUseId = block.id;
|
|
394
|
+
result.toolCalls += 1;
|
|
395
|
+
|
|
396
|
+
assistantContent.push({
|
|
397
|
+
type: 'tool_use',
|
|
398
|
+
id: toolUseId,
|
|
399
|
+
name: toolName,
|
|
400
|
+
input: toolInput,
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Pre-tool hook (supervised mode)
|
|
404
|
+
if (this._preToolHook) {
|
|
405
|
+
const approved = this._preToolHook(toolName, toolInput);
|
|
406
|
+
if (!approved) {
|
|
407
|
+
result.steps.push(`[blocked] ${toolName}`);
|
|
408
|
+
toolResults.push({
|
|
409
|
+
type: 'tool_result',
|
|
410
|
+
tool_use_id: toolUseId,
|
|
411
|
+
content: 'Tool execution blocked by supervisor.',
|
|
412
|
+
});
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Build step description
|
|
418
|
+
let stepDesc = `[tool] ${toolName}`;
|
|
419
|
+
if (toolName === 'sandbox_exec') {
|
|
420
|
+
stepDesc += `: ${(toolInput.command || '').slice(0, 80)}`;
|
|
421
|
+
} else if (toolName === 'http_request') {
|
|
422
|
+
stepDesc += `: ${toolInput.method || 'GET'} ${toolInput.url || ''}`;
|
|
423
|
+
} else if (toolName === 'read_file') {
|
|
424
|
+
stepDesc += `: ${toolInput.path || ''}`;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
debug(`Dispatching: ${stepDesc}`);
|
|
428
|
+
result.steps.push(stepDesc);
|
|
429
|
+
|
|
430
|
+
// Dispatch tool (ToolRegistry catches handler exceptions)
|
|
431
|
+
const toolOutput = this._config.toolRegistry.dispatch(
|
|
432
|
+
toolName, toolInput, this._context,
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
// Check completion on tool output
|
|
436
|
+
if (this._config.completionCheck !== null && this._config.completionCheck(toolOutput)) {
|
|
437
|
+
completed = true;
|
|
438
|
+
completedText = toolOutput;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
toolResults.push({
|
|
442
|
+
type: 'tool_result',
|
|
443
|
+
tool_use_id: toolUseId,
|
|
444
|
+
content: toolOutput,
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Track last assistant text for outputParser
|
|
450
|
+
if (turnTextParts.length > 0) {
|
|
451
|
+
lastAssistantText = turnTextParts.join('');
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Add assistant response to message history
|
|
455
|
+
messages.push({ role: 'assistant', content: assistantContent });
|
|
456
|
+
|
|
457
|
+
// If completion check fired, we're done
|
|
458
|
+
if (completed) {
|
|
459
|
+
result.steps.push(
|
|
460
|
+
`[complete] Completion check passed: ${completedText.slice(0, 200)}`
|
|
461
|
+
);
|
|
462
|
+
exhausted = false;
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
// If no tool_use in response, LLM is done
|
|
467
|
+
const stopReason = response.stop_reason ?? null;
|
|
468
|
+
if (stopReason !== 'tool_use') {
|
|
469
|
+
debug(`Agent stopped: stop_reason=${stopReason}`);
|
|
470
|
+
result.steps.push(`[end] Agent stopped (reason: ${stopReason})`);
|
|
471
|
+
exhausted = false;
|
|
472
|
+
break;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Continue with tool results
|
|
476
|
+
if (toolResults.length > 0) {
|
|
477
|
+
messages.push({ role: 'user', content: toolResults });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Loop exhausted without break (for...else equivalent)
|
|
482
|
+
if (exhausted) {
|
|
483
|
+
result.steps.push(`[limit] Max turns (${this._config.maxTurns}) reached`);
|
|
484
|
+
debug(`Agent exhausted ${this._config.maxTurns} turns`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// --- Post-loop: output parsing ---
|
|
488
|
+
if (this._config.outputParser !== null) {
|
|
489
|
+
try {
|
|
490
|
+
result.outputData = this._config.outputParser(lastAssistantText);
|
|
491
|
+
} catch (e) {
|
|
492
|
+
const parseErr = `Output parser error: ${e.constructor.name}: ${e.message}`;
|
|
493
|
+
if (result.error) {
|
|
494
|
+
result.error += `; ${parseErr}`;
|
|
495
|
+
} else {
|
|
496
|
+
result.error = parseErr;
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Set output text
|
|
502
|
+
result.outputText = lastAssistantText;
|
|
503
|
+
|
|
504
|
+
// --- Post-loop: validation ---
|
|
505
|
+
result.validation = this._config.validator.validate(result);
|
|
506
|
+
|
|
507
|
+
// --- Duration ---
|
|
508
|
+
result.durationS = (performance.now() / 1000) - startTime;
|
|
509
|
+
|
|
510
|
+
return result;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Copyright (c) 2026 defconxt. All rights reserved.
|
|
2
|
+
// Licensed under AGPL-3.0 — see LICENSE file for details.
|
|
3
|
+
// CIPHER is a trademark of defconxt.
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Barrel export for the autonomous framework.
|
|
7
|
+
*
|
|
8
|
+
* Re-exports all framework primitives, validators, runner, and mode symbols.
|
|
9
|
+
*
|
|
10
|
+
* @module autonomous
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// Framework primitives
|
|
14
|
+
export {
|
|
15
|
+
truncateOutput,
|
|
16
|
+
ValidationResult,
|
|
17
|
+
ModeAgentResult,
|
|
18
|
+
ToolRegistry,
|
|
19
|
+
NullValidator,
|
|
20
|
+
ModeAgentConfig,
|
|
21
|
+
BaseAgent,
|
|
22
|
+
} from './framework.js';
|
|
23
|
+
|
|
24
|
+
// Validators
|
|
25
|
+
export { SigmaValidator } from './validators/sigma.js';
|
|
26
|
+
export { ForensicValidator } from './validators/forensic.js';
|
|
27
|
+
export { PurpleValidator } from './validators/purple.js';
|
|
28
|
+
export { OSINTValidator } from './validators/osint.js';
|
|
29
|
+
export { DPIAValidator } from './validators/privacy.js';
|
|
30
|
+
export { ThreatModelValidator } from './validators/threat-model.js';
|
|
31
|
+
|
|
32
|
+
// Sigma validator helpers (used by PurpleValidator and tests)
|
|
33
|
+
export { stripCodeFences, parseYamlDocuments } from './validators/sigma.js';
|
|
34
|
+
|
|
35
|
+
// Runner — mode registry, FlagValidator, and dispatch
|
|
36
|
+
export {
|
|
37
|
+
registerMode,
|
|
38
|
+
availableModes,
|
|
39
|
+
initModes,
|
|
40
|
+
getModeRegistry,
|
|
41
|
+
FlagValidator,
|
|
42
|
+
FLAG_PATTERN,
|
|
43
|
+
_resetModes,
|
|
44
|
+
makeAgentClient,
|
|
45
|
+
runAutonomous,
|
|
46
|
+
} from './runner.js';
|
|
47
|
+
|
|
48
|
+
// Mode-specific exports needed downstream
|
|
49
|
+
export { ATTACK_TECHNIQUES } from './modes/blue.js';
|
|
50
|
+
|
|
51
|
+
// Phase 4 — Scheduler
|
|
52
|
+
export {
|
|
53
|
+
TaskPriority,
|
|
54
|
+
SchedulerState,
|
|
55
|
+
ScheduledTask,
|
|
56
|
+
TaskResult,
|
|
57
|
+
LastRequestTracker,
|
|
58
|
+
IdleDetector,
|
|
59
|
+
CipherScheduler,
|
|
60
|
+
createDefaultTasks,
|
|
61
|
+
} from './scheduler.js';
|
|
62
|
+
|
|
63
|
+
// Phase 4 — Researcher
|
|
64
|
+
export {
|
|
65
|
+
ResearchHypothesis,
|
|
66
|
+
ResearchExperiment,
|
|
67
|
+
SkillGapAnalyzer,
|
|
68
|
+
AutonomousResearcher,
|
|
69
|
+
} from './researcher.js';
|
|
70
|
+
|
|
71
|
+
// Phase 4 — Parallel
|
|
72
|
+
export {
|
|
73
|
+
AgentTask,
|
|
74
|
+
AgentResult,
|
|
75
|
+
WorkerPool,
|
|
76
|
+
ParallelScanner,
|
|
77
|
+
ParallelAnalyzer,
|
|
78
|
+
TaskOrchestrator,
|
|
79
|
+
} from './parallel.js';
|
|
80
|
+
|
|
81
|
+
// Phase 4 — Leaderboard
|
|
82
|
+
export {
|
|
83
|
+
SkillMetric,
|
|
84
|
+
DomainMetric,
|
|
85
|
+
LeaderboardEntry,
|
|
86
|
+
SkillLeaderboard,
|
|
87
|
+
} from './leaderboard.js';
|
|
88
|
+
|
|
89
|
+
// Phase 4 — Feedback Loop
|
|
90
|
+
export {
|
|
91
|
+
ImprovementStatus,
|
|
92
|
+
ImprovementCandidate,
|
|
93
|
+
ImprovementCycle,
|
|
94
|
+
SkillQualityAnalyzer,
|
|
95
|
+
FeedbackLoop,
|
|
96
|
+
connectLeaderboardToResearcher,
|
|
97
|
+
} from './feedback-loop.js';
|