@sschepis/robodev 1.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/ai.mjs +8 -0
- package/package.json +48 -0
- package/src/cli/cli-interface.mjs +271 -0
- package/src/config.mjs +64 -0
- package/src/core/ai-assistant.mjs +540 -0
- package/src/core/ai-provider.mjs +579 -0
- package/src/core/history-manager.mjs +330 -0
- package/src/core/system-prompt.mjs +182 -0
- package/src/custom-tools/custom-tools-manager.mjs +310 -0
- package/src/execution/tool-executor.mjs +892 -0
- package/src/lib/README.md +114 -0
- package/src/lib/adapters/console-status-adapter.mjs +48 -0
- package/src/lib/adapters/network-llm-adapter.mjs +37 -0
- package/src/lib/index.mjs +101 -0
- package/src/lib/interfaces.d.ts +98 -0
- package/src/main.mjs +61 -0
- package/src/package/package-manager.mjs +223 -0
- package/src/quality/code-validator.mjs +126 -0
- package/src/quality/quality-evaluator.mjs +248 -0
- package/src/reasoning/reasoning-system.mjs +258 -0
- package/src/structured-dev/flow-manager.mjs +321 -0
- package/src/structured-dev/implementation-planner.mjs +223 -0
- package/src/structured-dev/manifest-manager.mjs +423 -0
- package/src/structured-dev/plan-executor.mjs +113 -0
- package/src/structured-dev/project-bootstrapper.mjs +523 -0
- package/src/tools/desktop-automation-tools.mjs +172 -0
- package/src/tools/file-tools.mjs +141 -0
- package/src/tools/tool-definitions.mjs +872 -0
- package/src/ui/console-styler.mjs +503 -0
- package/src/workspace/workspace-manager.mjs +215 -0
- package/themes.json +66 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// Code Validator
|
|
2
|
+
// Performs real-time validation (linting, type-checking) on files
|
|
3
|
+
// to provide immediate feedback to AI agents.
|
|
4
|
+
|
|
5
|
+
import { exec } from 'child_process';
|
|
6
|
+
import util from 'util';
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import { consoleStyler } from '../ui/console-styler.mjs';
|
|
10
|
+
|
|
11
|
+
const execPromise = util.promisify(exec);
|
|
12
|
+
|
|
13
|
+
export class CodeValidator {
|
|
14
|
+
constructor(workingDir) {
|
|
15
|
+
this.workingDir = workingDir;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Validates a file based on its extension.
|
|
20
|
+
* @param {string} filePath - Relative path to the file
|
|
21
|
+
* @returns {Promise<string|null>} - Formatted error string or null if valid
|
|
22
|
+
*/
|
|
23
|
+
async validateFile(filePath) {
|
|
24
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
25
|
+
const fullPath = path.resolve(this.workingDir, filePath);
|
|
26
|
+
|
|
27
|
+
// Only validate if file exists
|
|
28
|
+
if (!fs.existsSync(fullPath)) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
if (['.ts', '.tsx'].includes(ext)) {
|
|
34
|
+
return await this.validateTypeScript(filePath);
|
|
35
|
+
} else if (['.js', '.mjs', '.jsx'].includes(ext)) {
|
|
36
|
+
return await this.validateJavaScript(filePath);
|
|
37
|
+
}
|
|
38
|
+
} catch (error) {
|
|
39
|
+
// If validation command fails (e.g. tsc not found), log it but don't break the tool
|
|
40
|
+
consoleStyler.log('error', `Validation tool error: ${error.message}`);
|
|
41
|
+
return `(Validation tool failed: ${error.message})`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
async validateTypeScript(filePath) {
|
|
48
|
+
// Run tsc on the specific file
|
|
49
|
+
// --noEmit: Don't generate JS
|
|
50
|
+
// --skipLibCheck: Speed up
|
|
51
|
+
// --allowJs: Allow JS files in check if needed
|
|
52
|
+
// --pretty false: output parseable text
|
|
53
|
+
// We use npx to use local or cached tsc
|
|
54
|
+
// Increased resilience with project root finding logic could go here,
|
|
55
|
+
// but cwd execution is usually sufficient for relative paths.
|
|
56
|
+
|
|
57
|
+
const cmd = `npx tsc --noEmit --skipLibCheck --allowJs --target es2020 --moduleResolution node --pretty false "${filePath}"`;
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
await execPromise(cmd, { cwd: this.workingDir, timeout: 30000 }); // 30s timeout
|
|
61
|
+
return null; // Success = no output/errors
|
|
62
|
+
} catch (error) {
|
|
63
|
+
// timeout error
|
|
64
|
+
if (error.signal === 'SIGTERM') {
|
|
65
|
+
return `Validation timed out after 30s for ${filePath}`;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// tsc exits with non-zero if errors found
|
|
69
|
+
// stdout contains the errors
|
|
70
|
+
const output = error.stdout || error.stderr;
|
|
71
|
+
return this.formatOutput(output, filePath);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
async validateJavaScript(filePath) {
|
|
76
|
+
// Try ESLint first
|
|
77
|
+
try {
|
|
78
|
+
const eslintCmd = `npx eslint --no-color --format unix "${filePath}"`;
|
|
79
|
+
await execPromise(eslintCmd, { cwd: this.workingDir, timeout: 20000 });
|
|
80
|
+
return null;
|
|
81
|
+
} catch (error) {
|
|
82
|
+
// If eslint fails due to config missing or errors found
|
|
83
|
+
if (error.stdout && (error.stdout.includes(filePath) || error.stdout.includes('error'))) {
|
|
84
|
+
return this.formatOutput(error.stdout, filePath);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Fallback: Syntax check with node
|
|
88
|
+
try {
|
|
89
|
+
// node -c checks syntax
|
|
90
|
+
const nodeCmd = `node --check "${filePath}"`;
|
|
91
|
+
await execPromise(nodeCmd, { cwd: this.workingDir, timeout: 10000 });
|
|
92
|
+
return null;
|
|
93
|
+
} catch (syntaxError) {
|
|
94
|
+
return `Syntax Error: ${syntaxError.stderr.trim()}`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
formatOutput(output, filePath) {
|
|
100
|
+
if (!output) return null;
|
|
101
|
+
|
|
102
|
+
// Clean up ANSI codes if any remain (though we try to suppress them)
|
|
103
|
+
const cleanOutput = output.replace(/\u001b\[[0-9;]*m/g, '');
|
|
104
|
+
|
|
105
|
+
const lines = cleanOutput.split('\n');
|
|
106
|
+
|
|
107
|
+
// Filter lines relevant to the file or generic errors
|
|
108
|
+
// We want to capture the specific error lines, usually formatted like "file.ts(1,1): error ..."
|
|
109
|
+
const fileName = path.basename(filePath);
|
|
110
|
+
const relevantLines = lines.filter(line =>
|
|
111
|
+
line.includes(fileName) ||
|
|
112
|
+
line.includes('error TS') ||
|
|
113
|
+
(line.includes('Error:') && !line.includes('Validation tool error'))
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if (relevantLines.length === 0) return null;
|
|
117
|
+
|
|
118
|
+
// Limit output size to prevent context flooding
|
|
119
|
+
const MAX_LINES = 15;
|
|
120
|
+
if (relevantLines.length > MAX_LINES) {
|
|
121
|
+
return relevantLines.slice(0, MAX_LINES).join('\n') + `\n... (${relevantLines.length - MAX_LINES} more errors truncated)`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return relevantLines.join('\n');
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// Quality evaluation system
|
|
2
|
+
// Handles response quality evaluation and retry logic
|
|
3
|
+
|
|
4
|
+
import { consoleStyler } from '../ui/console-styler.mjs';
|
|
5
|
+
import { ENHANCEMENT_TOOLS } from '../tools/tool-definitions.mjs';
|
|
6
|
+
import { callProvider } from '../core/ai-provider.mjs';
|
|
7
|
+
|
|
8
|
+
export class QualityEvaluator {
|
|
9
|
+
constructor(endpoint) {
|
|
10
|
+
this.endpoint = endpoint; // kept for backward compatibility
|
|
11
|
+
this.qualityIssue = null;
|
|
12
|
+
this.retryAttempts = 0;
|
|
13
|
+
this.maxRetryAttempts = 2;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Evaluate response quality using AI
|
|
17
|
+
async evaluateResponse(userInput, finalResponse, toolCallsSummary, toolResults, createSystemPrompt, workingDir, workspace) {
|
|
18
|
+
// Don't evaluate if we've already exceeded retry attempts
|
|
19
|
+
if (this.retryAttempts >= this.maxRetryAttempts) {
|
|
20
|
+
consoleStyler.log('quality', `Skipping quality evaluation - max retry attempts (${this.maxRetryAttempts}) reached`);
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
consoleStyler.log('quality', 'Preparing comprehensive quality evaluation context...');
|
|
25
|
+
|
|
26
|
+
// Create comprehensive context for quality evaluation
|
|
27
|
+
let evaluationContext = `Please evaluate the quality of this AI response using the evaluate_response_quality tool:
|
|
28
|
+
|
|
29
|
+
ORIGINAL QUERY: "${userInput}"
|
|
30
|
+
|
|
31
|
+
AI RESPONSE: "${finalResponse}"`;
|
|
32
|
+
|
|
33
|
+
if (toolCallsSummary.length > 0) {
|
|
34
|
+
evaluationContext += `
|
|
35
|
+
|
|
36
|
+
TOOLS USED BY AI:`;
|
|
37
|
+
toolCallsSummary.forEach((call, i) => {
|
|
38
|
+
evaluationContext += `
|
|
39
|
+
${i + 1}. ${call.tool}(${Object.entries(call.parameters).map(([k,v]) => `${k}: ${JSON.stringify(v)}`).join(', ')})`;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (toolResults.length > 0) {
|
|
43
|
+
evaluationContext += `
|
|
44
|
+
|
|
45
|
+
TOOL RESULTS:`;
|
|
46
|
+
toolResults.forEach((result, i) => {
|
|
47
|
+
let resultStr = typeof result.result === 'string' ? result.result : JSON.stringify(result.result);
|
|
48
|
+
if (resultStr === undefined) resultStr = 'undefined';
|
|
49
|
+
evaluationContext += `
|
|
50
|
+
${i + 1}. ${result.tool}: ${resultStr.substring(0, 200)}${resultStr.length > 200 ? '...' : ''}`;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
evaluationContext += `
|
|
56
|
+
|
|
57
|
+
EVALUATION CRITERIA:
|
|
58
|
+
- 10 = Perfect response that fully addresses the query (consider both text response AND tool usage)
|
|
59
|
+
- 7-9 = Good response with minor issues
|
|
60
|
+
- 4-6 = Adequate but could be improved
|
|
61
|
+
- 1-3 = Poor response that doesn't address the query properly
|
|
62
|
+
|
|
63
|
+
IMPORTANT: When evaluating, consider BOTH the text response AND the tools that were called. If the user asked for something to be done and the AI called the appropriate tools successfully, that should be reflected in the quality score even if the text response is brief.
|
|
64
|
+
|
|
65
|
+
If rating < 4, provide specific remedy suggestions.`;
|
|
66
|
+
|
|
67
|
+
// Create a quality evaluation request
|
|
68
|
+
const qualityCheckHistory = [
|
|
69
|
+
{ role: 'system', content: createSystemPrompt(workingDir, workspace) },
|
|
70
|
+
{
|
|
71
|
+
role: 'user',
|
|
72
|
+
content: evaluationContext
|
|
73
|
+
}
|
|
74
|
+
];
|
|
75
|
+
|
|
76
|
+
consoleStyler.log('quality', `Evaluating response quality with ${toolCallsSummary.length} tool calls and ${toolResults.length} tool results`);
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
// Import config dynamically to avoid circular dependencies
|
|
80
|
+
const { config } = await import('../config.mjs');
|
|
81
|
+
|
|
82
|
+
const qualityResult = await callProvider({
|
|
83
|
+
model: config.ai.model,
|
|
84
|
+
messages: qualityCheckHistory,
|
|
85
|
+
tools: ENHANCEMENT_TOOLS,
|
|
86
|
+
tool_choice: { type: "function", function: { name: "evaluate_response_quality" } },
|
|
87
|
+
temperature: 0.1,
|
|
88
|
+
reasoning_effort: "high" // Quality evaluation always uses high reasoning
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (qualityResult && qualityResult.choices) {
|
|
92
|
+
const qualityMessage = qualityResult.choices[0].message;
|
|
93
|
+
|
|
94
|
+
if (qualityMessage.tool_calls && qualityMessage.tool_calls.length > 0) {
|
|
95
|
+
for (const toolCall of qualityMessage.tool_calls) {
|
|
96
|
+
if (toolCall.function.name === 'evaluate_response_quality') {
|
|
97
|
+
const args = JSON.parse(toolCall.function.arguments);
|
|
98
|
+
const { quality_rating = 0, evaluation_reasoning = "No reasoning provided", remedy_suggestion = "" } = args;
|
|
99
|
+
|
|
100
|
+
consoleStyler.log('quality', `Quality evaluation results:`);
|
|
101
|
+
consoleStyler.log('quality', ` Rating: ${quality_rating}/10`, { indent: true });
|
|
102
|
+
if (evaluation_reasoning && typeof evaluation_reasoning === 'string') {
|
|
103
|
+
consoleStyler.log('quality', ` Reasoning: ${evaluation_reasoning.substring(0, 100)}...`, { indent: true });
|
|
104
|
+
}
|
|
105
|
+
if (remedy_suggestion && typeof remedy_suggestion === 'string') {
|
|
106
|
+
consoleStyler.log('quality', ` Remedy: ${remedy_suggestion.substring(0, 100)}...`, { indent: true });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
rating: quality_rating,
|
|
111
|
+
reasoning: evaluation_reasoning,
|
|
112
|
+
remedy: remedy_suggestion,
|
|
113
|
+
needsRetry: quality_rating < 4 && remedy_suggestion
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
} catch (qualityError) {
|
|
120
|
+
consoleStyler.log('error', `Quality evaluation failed: ${qualityError.message}`, { box: true });
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
consoleStyler.log('quality', 'Quality evaluation completed with no actionable results');
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
// Check if retry is needed based on quality evaluation
|
|
128
|
+
shouldRetry(qualityResult) {
|
|
129
|
+
if (!qualityResult || !qualityResult.needsRetry) {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (this.retryAttempts >= this.maxRetryAttempts) {
|
|
134
|
+
consoleStyler.log('quality', `Maximum retry attempts (${this.maxRetryAttempts}) reached`);
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Create improved prompt for retry
|
|
142
|
+
createRetryPrompt(userInput, finalResponse, qualityResult) {
|
|
143
|
+
this.retryAttempts++;
|
|
144
|
+
|
|
145
|
+
consoleStyler.log('quality', `Poor quality detected (${qualityResult.rating}/10)`, { box: true });
|
|
146
|
+
consoleStyler.log('quality', `Remedy: ${qualityResult.remedy}`);
|
|
147
|
+
|
|
148
|
+
// Store quality issue for reference
|
|
149
|
+
this.qualityIssue = {
|
|
150
|
+
rating: qualityResult.rating,
|
|
151
|
+
reasoning: qualityResult.reasoning,
|
|
152
|
+
remedy: qualityResult.remedy,
|
|
153
|
+
original_query: userInput,
|
|
154
|
+
poor_response: finalResponse
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Create improved prompt with remedy
|
|
158
|
+
const improvedPrompt = `${userInput}
|
|
159
|
+
|
|
160
|
+
PREVIOUS RESPONSE WAS INADEQUATE (rated ${qualityResult.rating}/10):
|
|
161
|
+
"${finalResponse}"
|
|
162
|
+
|
|
163
|
+
REMEDY REQUIRED: ${qualityResult.remedy}
|
|
164
|
+
|
|
165
|
+
Please provide a better response that addresses these quality issues.`;
|
|
166
|
+
|
|
167
|
+
return improvedPrompt;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Reset quality evaluation state
|
|
171
|
+
reset() {
|
|
172
|
+
this.qualityIssue = null;
|
|
173
|
+
this.retryAttempts = 0;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Get current quality issue
|
|
177
|
+
getQualityIssue() {
|
|
178
|
+
return this.qualityIssue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Get retry attempt count
|
|
182
|
+
getRetryAttempts() {
|
|
183
|
+
return this.retryAttempts;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Set quality issue manually (for tool execution)
|
|
187
|
+
setQualityIssue(issue) {
|
|
188
|
+
this.qualityIssue = issue;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// Check if we're currently in a retry situation
|
|
192
|
+
isRetrying() {
|
|
193
|
+
return this.retryAttempts > 0;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Get quality evaluation summary for logging
|
|
197
|
+
getQualitySummary() {
|
|
198
|
+
if (!this.qualityIssue) {
|
|
199
|
+
return "No quality issues detected";
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return `Quality issue: ${this.qualityIssue.rating}/10 - ${this.qualityIssue.remedy}`;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Handle quality evaluation result from tool execution
|
|
206
|
+
handleQualityToolResult(args) {
|
|
207
|
+
const { quality_rating = 0, evaluation_reasoning = "No reasoning", remedy_suggestion = "" } = args;
|
|
208
|
+
|
|
209
|
+
if (quality_rating < 4) {
|
|
210
|
+
console.log(`\x1b[31m[QUALITY] Poor quality detected (${quality_rating}/10)\x1b[0m`);
|
|
211
|
+
if (remedy_suggestion) {
|
|
212
|
+
console.log(`\x1b[33m[QUALITY] Remedy: ${remedy_suggestion}\x1b[0m`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Store quality issue for retry
|
|
216
|
+
this.qualityIssue = {
|
|
217
|
+
rating: quality_rating,
|
|
218
|
+
reasoning: evaluation_reasoning,
|
|
219
|
+
remedy: remedy_suggestion
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return `Quality rating ${quality_rating}/10 - retry needed with remedy: ${remedy_suggestion}`;
|
|
223
|
+
} else {
|
|
224
|
+
return `Quality rating ${quality_rating}/10 - response approved`;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Extract tool call summary for quality evaluation
|
|
229
|
+
extractToolCallsSummary(history) {
|
|
230
|
+
return history
|
|
231
|
+
.filter(msg => msg.tool_calls && msg.tool_calls.length > 0)
|
|
232
|
+
.map(msg => msg.tool_calls.map(call => ({
|
|
233
|
+
tool: call.function.name,
|
|
234
|
+
parameters: JSON.parse(call.function.arguments)
|
|
235
|
+
})))
|
|
236
|
+
.flat();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// Extract tool results for quality evaluation
|
|
240
|
+
extractToolResults(history) {
|
|
241
|
+
return history
|
|
242
|
+
.filter(msg => msg.role === 'tool')
|
|
243
|
+
.map(msg => ({
|
|
244
|
+
tool: msg.name,
|
|
245
|
+
result: msg.content
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
// Reasoning system for determining appropriate effort levels
|
|
2
|
+
// This module handles all logic related to determining how much reasoning effort to apply
|
|
3
|
+
|
|
4
|
+
import { consoleStyler } from '../ui/console-styler.mjs';
|
|
5
|
+
|
|
6
|
+
export class ReasoningSystem {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.errorHistory = [];
|
|
9
|
+
this.predictedReasoning = null;
|
|
10
|
+
this.reasoningJustification = null;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Determine reasoning effort based on task complexity
|
|
14
|
+
determineReasoningEffort(userInput, context = {}) {
|
|
15
|
+
// Check for user preference first
|
|
16
|
+
const userPreference = this.parseUserReasoningPreference(userInput);
|
|
17
|
+
if (userPreference) return userPreference;
|
|
18
|
+
|
|
19
|
+
// Check for complexity indicators
|
|
20
|
+
const complexityIndicators = {
|
|
21
|
+
high: [
|
|
22
|
+
/debug|troubleshoot|analyze error/i,
|
|
23
|
+
/architect|design|plan/i,
|
|
24
|
+
/optimize|refactor|improve performance/i,
|
|
25
|
+
/complex|complicated|multi-step/i,
|
|
26
|
+
/why|explain|understand/i,
|
|
27
|
+
/embellish|enhance|improve/i
|
|
28
|
+
],
|
|
29
|
+
medium: [
|
|
30
|
+
/create|build|implement/i,
|
|
31
|
+
/fix|solve|resolve/i,
|
|
32
|
+
/convert|transform/i,
|
|
33
|
+
/test|validate/i,
|
|
34
|
+
/fetch|scrape|extract/i
|
|
35
|
+
],
|
|
36
|
+
low: [
|
|
37
|
+
/simple|basic|quick/i,
|
|
38
|
+
/list|show|display/i,
|
|
39
|
+
/check|verify/i,
|
|
40
|
+
/format|clean/i,
|
|
41
|
+
/update status/i
|
|
42
|
+
]
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Check if we're in a recovery/retry situation
|
|
46
|
+
if (context.isRetry || context.errorCount > 0) {
|
|
47
|
+
consoleStyler.log('reasoning', 'Using high effort due to retry/error context');
|
|
48
|
+
return "high";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Check if we have a todo list with many steps
|
|
52
|
+
if (context.todoCount && context.todoCount > 5) {
|
|
53
|
+
consoleStyler.log('reasoning', 'Using high effort due to complex multi-step task');
|
|
54
|
+
return "high";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Pattern matching
|
|
58
|
+
for (const [level, patterns] of Object.entries(complexityIndicators)) {
|
|
59
|
+
if (patterns.some(pattern => pattern.test(userInput))) {
|
|
60
|
+
consoleStyler.log('reasoning', `Detected ${level} complexity from input patterns`);
|
|
61
|
+
return level;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return "medium"; // Default
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Parse user preference for reasoning level
|
|
69
|
+
parseUserReasoningPreference(userInput) {
|
|
70
|
+
const reasoningHints = {
|
|
71
|
+
high: /\b(carefully|thoroughly|deeply|detailed|comprehensive)\b/i,
|
|
72
|
+
low: /\b(quickly|briefly|simple|fast|quick)\b/i
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
for (const [level, pattern] of Object.entries(reasoningHints)) {
|
|
76
|
+
if (pattern.test(userInput)) {
|
|
77
|
+
consoleStyler.log('reasoning', `User requested ${level} effort`);
|
|
78
|
+
return level;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null; // No preference detected
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Get adaptive reasoning based on error history
|
|
86
|
+
getAdaptiveReasoningEffort() {
|
|
87
|
+
const recentErrors = this.errorHistory.filter(err => {
|
|
88
|
+
const errorTime = new Date(err.timestamp);
|
|
89
|
+
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
|
|
90
|
+
return errorTime > fiveMinutesAgo;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
if (recentErrors.length >= 3) {
|
|
94
|
+
consoleStyler.log('reasoning', `Using high effort due to ${recentErrors.length} recent errors`);
|
|
95
|
+
return "high";
|
|
96
|
+
}
|
|
97
|
+
if (recentErrors.length >= 1) {
|
|
98
|
+
consoleStyler.log('reasoning', 'Using medium effort due to recent errors');
|
|
99
|
+
return "medium";
|
|
100
|
+
}
|
|
101
|
+
return "low";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Get tool-specific reasoning level
|
|
105
|
+
getToolSpecificReasoning(toolName) {
|
|
106
|
+
const toolReasoningMap = {
|
|
107
|
+
'analyze_and_recover': 'high', // Error recovery needs deep thinking
|
|
108
|
+
'embellish_request': 'high', // Planning needs thorough analysis
|
|
109
|
+
'execute_javascript': 'medium', // Code execution is straightforward
|
|
110
|
+
'create_todo_list': 'high', // Planning multi-step tasks
|
|
111
|
+
'update_todo_status': 'low', // Simple status update
|
|
112
|
+
'evaluate_response_quality': 'high' // Quality evaluation needs careful analysis
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const level = toolReasoningMap[toolName] || 'medium';
|
|
116
|
+
consoleStyler.log('reasoning', `Using ${level} effort for tool: ${toolName}`);
|
|
117
|
+
return level;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Get context-aware reasoning based on conversation state
|
|
121
|
+
getContextAwareReasoning(context = {}) {
|
|
122
|
+
const { historyLength = 0, toolCallCount = 0, pendingSteps = 0 } = context;
|
|
123
|
+
|
|
124
|
+
// Long conversations might need more reasoning
|
|
125
|
+
if (historyLength > 20) {
|
|
126
|
+
consoleStyler.log('reasoning', 'Using high effort due to long conversation history');
|
|
127
|
+
return "high";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Multiple tool calls in history suggest complex task
|
|
131
|
+
if (toolCallCount > 5) {
|
|
132
|
+
consoleStyler.log('reasoning', 'Using high effort due to multiple tool calls');
|
|
133
|
+
return "high";
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Check if we're in the middle of a multi-step process
|
|
137
|
+
if (pendingSteps > 3) {
|
|
138
|
+
consoleStyler.log('reasoning', `Using high effort due to ${pendingSteps} pending steps`);
|
|
139
|
+
return "high";
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return "medium";
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Combine all reasoning strategies to determine final effort level
|
|
146
|
+
determineOptimalReasoning(userInput = null, toolName = null, context = {}) {
|
|
147
|
+
// Priority order for reasoning determination
|
|
148
|
+
// 1. Tool-specific reasoning (if tool is being used)
|
|
149
|
+
if (toolName) {
|
|
150
|
+
return this.getToolSpecificReasoning(toolName);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 2. Error-based adaptive reasoning
|
|
154
|
+
const errorBasedReasoning = this.getAdaptiveReasoningEffort();
|
|
155
|
+
if (errorBasedReasoning === "high") {
|
|
156
|
+
return errorBasedReasoning;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 3. Context-aware reasoning
|
|
160
|
+
const contextReasoning = this.getContextAwareReasoning(context);
|
|
161
|
+
if (contextReasoning === "high") {
|
|
162
|
+
return contextReasoning;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 4. Task complexity reasoning
|
|
166
|
+
const complexityReasoning = this.determineReasoningEffort(userInput || '', {
|
|
167
|
+
isRetry: context.retryAttempts > 0,
|
|
168
|
+
errorCount: this.errorHistory.length,
|
|
169
|
+
todoCount: context.todoCount
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
// Return the highest reasoning level among all strategies
|
|
173
|
+
const levels = [errorBasedReasoning, contextReasoning, complexityReasoning];
|
|
174
|
+
if (levels.includes("high")) return "high";
|
|
175
|
+
if (levels.includes("medium")) return "medium";
|
|
176
|
+
return "low";
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Add error to history for adaptive reasoning
|
|
180
|
+
addError(error) {
|
|
181
|
+
this.errorHistory.push({
|
|
182
|
+
error: error.message,
|
|
183
|
+
timestamp: new Date().toISOString()
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Set predicted reasoning from embellishment
|
|
188
|
+
setPredictedReasoning(reasoning, justification) {
|
|
189
|
+
this.predictedReasoning = reasoning;
|
|
190
|
+
this.reasoningJustification = justification;
|
|
191
|
+
consoleStyler.log('reasoning', `Predicted: ${reasoning} - ${justification}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Get predicted reasoning
|
|
195
|
+
getPredictedReasoning() {
|
|
196
|
+
return this.predictedReasoning;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Get simplified reasoning with minimal logic for performance
|
|
200
|
+
getSimplifiedReasoning(userInput = '', context = {}) {
|
|
201
|
+
// Critical overrides only
|
|
202
|
+
const recentErrors = this.errorHistory.filter(err => {
|
|
203
|
+
const errorTime = new Date(err.timestamp);
|
|
204
|
+
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
|
|
205
|
+
return errorTime > fiveMinutesAgo;
|
|
206
|
+
}).length;
|
|
207
|
+
|
|
208
|
+
if (recentErrors >= 2) {
|
|
209
|
+
consoleStyler.log('reasoning', `Override: high due to ${recentErrors} recent errors`);
|
|
210
|
+
return "high";
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (context.toolName === 'analyze_and_recover' || context.toolName === 'evaluate_response_quality') {
|
|
214
|
+
consoleStyler.log('reasoning', `Override: high for ${context.toolName}`);
|
|
215
|
+
return "high";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if (this.predictedReasoning) {
|
|
219
|
+
consoleStyler.log('reasoning', `Using predicted: ${this.predictedReasoning}`);
|
|
220
|
+
return this.predictedReasoning;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Default fallback
|
|
224
|
+
consoleStyler.log('reasoning', 'Using default: medium');
|
|
225
|
+
return "medium";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Reset reasoning state
|
|
229
|
+
reset() {
|
|
230
|
+
this.predictedReasoning = null;
|
|
231
|
+
this.reasoningJustification = null;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Simple heuristic-based reasoning prediction as fallback
|
|
235
|
+
predictReasoningFromInput(userInput) {
|
|
236
|
+
const lowerInput = userInput.toLowerCase();
|
|
237
|
+
|
|
238
|
+
if (lowerInput.includes('quickly') || lowerInput.includes('quick') ||
|
|
239
|
+
lowerInput.includes('fast') || lowerInput.includes('briefly')) {
|
|
240
|
+
this.predictedReasoning = 'low';
|
|
241
|
+
consoleStyler.log('reasoning', 'Detected user preference: low (quick/fast)');
|
|
242
|
+
} else if (lowerInput.includes('thoroughly') || lowerInput.includes('detailed') ||
|
|
243
|
+
lowerInput.includes('comprehensive') || lowerInput.includes('carefully')) {
|
|
244
|
+
this.predictedReasoning = 'high';
|
|
245
|
+
consoleStyler.log('reasoning', 'Detected user preference: high (thorough/detailed)');
|
|
246
|
+
} else if (lowerInput.includes('debug') || lowerInput.includes('analyze') ||
|
|
247
|
+
lowerInput.includes('troubleshoot') || lowerInput.includes('complex')) {
|
|
248
|
+
this.predictedReasoning = 'high';
|
|
249
|
+
consoleStyler.log('reasoning', 'Detected complexity: high (debug/analyze)');
|
|
250
|
+
} else if (lowerInput.includes('simple') || lowerInput.includes('basic') ||
|
|
251
|
+
lowerInput.includes('count') || lowerInput.includes('list')) {
|
|
252
|
+
this.predictedReasoning = 'low';
|
|
253
|
+
consoleStyler.log('reasoning', 'Detected simplicity: low (simple/basic)');
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return this.predictedReasoning;
|
|
257
|
+
}
|
|
258
|
+
}
|