@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,330 @@
|
|
|
1
|
+
// History management and token estimation
|
|
2
|
+
// Handles context limits and conversation history optimization
|
|
3
|
+
|
|
4
|
+
import { consoleStyler } from '../ui/console-styler.mjs';
|
|
5
|
+
import { config } from '../config.mjs';
|
|
6
|
+
|
|
7
|
+
// Average characters per token (approximate for English text)
|
|
8
|
+
const CHARS_PER_TOKEN = 4;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages conversation history, token estimation, and context limits.
|
|
12
|
+
*/
|
|
13
|
+
export class HistoryManager {
|
|
14
|
+
/**
|
|
15
|
+
* @param {number|null} maxTokens - Maximum allow tokens
|
|
16
|
+
* @param {number|null} contextWindowSize - Total context window size
|
|
17
|
+
*/
|
|
18
|
+
constructor(maxTokens = null, contextWindowSize = null) {
|
|
19
|
+
this.maxTokens = maxTokens || config.ai.maxTokens || 4096;
|
|
20
|
+
this.contextWindowSize = contextWindowSize || config.ai.contextWindowSize || 128000;
|
|
21
|
+
|
|
22
|
+
/** @type {Array<Object>} */
|
|
23
|
+
this.history = [];
|
|
24
|
+
this.systemMessage = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Initialize history with a system message
|
|
29
|
+
* @param {string} systemPrompt
|
|
30
|
+
*/
|
|
31
|
+
initialize(systemPrompt) {
|
|
32
|
+
this.systemMessage = {
|
|
33
|
+
role: 'system',
|
|
34
|
+
content: systemPrompt
|
|
35
|
+
};
|
|
36
|
+
this.history = [this.systemMessage];
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Add a message to history
|
|
41
|
+
* @param {string} role - 'user', 'assistant', 'system', or 'tool'
|
|
42
|
+
* @param {string} content - Message content
|
|
43
|
+
* @param {Array<Object>|null} toolCalls - Optional tool calls
|
|
44
|
+
* @param {string|null} toolCallId - Optional tool call ID
|
|
45
|
+
* @param {string|null} name - Optional name for tool messages
|
|
46
|
+
*/
|
|
47
|
+
addMessage(role, content, toolCalls = null, toolCallId = null, name = null) {
|
|
48
|
+
const message = { role, content };
|
|
49
|
+
|
|
50
|
+
if (toolCalls) {
|
|
51
|
+
message.tool_calls = toolCalls;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (toolCallId) {
|
|
55
|
+
message.tool_call_id = toolCallId;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (name) {
|
|
59
|
+
message.name = name;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.history.push(message);
|
|
63
|
+
|
|
64
|
+
// Check context limits and optimize if needed
|
|
65
|
+
this.enforceContextLimits();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Add a complete message object directly
|
|
70
|
+
* @param {Object} message
|
|
71
|
+
*/
|
|
72
|
+
pushMessage(message) {
|
|
73
|
+
this.history.push(message);
|
|
74
|
+
this.enforceContextLimits();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get the full history
|
|
79
|
+
* @returns {Array<Object>}
|
|
80
|
+
*/
|
|
81
|
+
getHistory() {
|
|
82
|
+
return this.history;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Update the system prompt
|
|
87
|
+
* @param {string} newContent
|
|
88
|
+
*/
|
|
89
|
+
updateSystemPrompt(newContent) {
|
|
90
|
+
if (this.history.length > 0 && this.history[0].role === 'system') {
|
|
91
|
+
this.history[0].content = newContent;
|
|
92
|
+
this.systemMessage.content = newContent;
|
|
93
|
+
} else {
|
|
94
|
+
this.systemMessage = { role: 'system', content: newContent };
|
|
95
|
+
this.history.unshift(this.systemMessage);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Delete specified number of exchanges from history (backwards)
|
|
101
|
+
* @param {number} count
|
|
102
|
+
* @returns {number} Number of exchanges deleted
|
|
103
|
+
*/
|
|
104
|
+
deleteHistoryExchanges(count) {
|
|
105
|
+
if (count <= 0) return 0;
|
|
106
|
+
|
|
107
|
+
let deletedExchanges = 0;
|
|
108
|
+
|
|
109
|
+
// Work backwards through history, preserving system message at index 0
|
|
110
|
+
for (let i = 0; i < count; i++) {
|
|
111
|
+
// Find the most recent complete exchange (user + assistant + any tools)
|
|
112
|
+
let foundUserMessage = false;
|
|
113
|
+
let messagesToDelete = [];
|
|
114
|
+
|
|
115
|
+
// Scan backwards from end of history
|
|
116
|
+
for (let j = this.history.length - 1; j > 0; j--) { // Start from index 1 to preserve system message
|
|
117
|
+
const message = this.history[j];
|
|
118
|
+
|
|
119
|
+
if (message.role === 'user' && !foundUserMessage) {
|
|
120
|
+
// Found the start of the exchange to delete
|
|
121
|
+
foundUserMessage = true;
|
|
122
|
+
messagesToDelete.unshift(j); // Add to beginning since we're going backwards
|
|
123
|
+
} else if (foundUserMessage) {
|
|
124
|
+
// Part of the exchange (assistant, tool responses)
|
|
125
|
+
messagesToDelete.unshift(j);
|
|
126
|
+
|
|
127
|
+
// Check if this completes an exchange (hit previous user message or system)
|
|
128
|
+
if (message.role === 'user' || message.role === 'system') {
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
} else if (message.role === 'assistant' || message.role === 'tool') {
|
|
132
|
+
// Dangling assistant/tool message, include it in deletion
|
|
133
|
+
messagesToDelete.unshift(j);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Delete the identified messages
|
|
138
|
+
if (messagesToDelete.length > 0) {
|
|
139
|
+
// Sort in descending order to delete from end first (preserves indices)
|
|
140
|
+
messagesToDelete.sort((a, b) => b - a);
|
|
141
|
+
for (const index of messagesToDelete) {
|
|
142
|
+
this.history.splice(index, 1);
|
|
143
|
+
}
|
|
144
|
+
deletedExchanges++;
|
|
145
|
+
} else {
|
|
146
|
+
// No more exchanges to delete
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
return deletedExchanges;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Reset history to just the system prompt
|
|
156
|
+
*/
|
|
157
|
+
reset() {
|
|
158
|
+
if (this.systemMessage) {
|
|
159
|
+
this.history = [this.systemMessage];
|
|
160
|
+
} else {
|
|
161
|
+
this.history = [];
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Set history to a specific set of messages (e.g. for retries)
|
|
167
|
+
* @param {Array<Object>} messages
|
|
168
|
+
*/
|
|
169
|
+
setHistory(messages) {
|
|
170
|
+
this.history = [...messages];
|
|
171
|
+
// Ensure system message is tracked
|
|
172
|
+
if (this.history.length > 0 && this.history[0].role === 'system') {
|
|
173
|
+
this.systemMessage = this.history[0];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Estimate token count for a string
|
|
179
|
+
* @param {string} text
|
|
180
|
+
* @returns {number}
|
|
181
|
+
*/
|
|
182
|
+
estimateTokens(text) {
|
|
183
|
+
if (!text) return 0;
|
|
184
|
+
return Math.ceil(text.length / CHARS_PER_TOKEN);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Estimate total tokens in history
|
|
189
|
+
* @returns {number}
|
|
190
|
+
*/
|
|
191
|
+
getTotalTokens() {
|
|
192
|
+
let total = 0;
|
|
193
|
+
for (const msg of this.history) {
|
|
194
|
+
// Content tokens
|
|
195
|
+
total += this.estimateTokens(msg.content || '');
|
|
196
|
+
|
|
197
|
+
// Role overhead (approximate)
|
|
198
|
+
total += 4;
|
|
199
|
+
|
|
200
|
+
// Tool calls tokens
|
|
201
|
+
if (msg.tool_calls) {
|
|
202
|
+
for (const call of msg.tool_calls) {
|
|
203
|
+
total += this.estimateTokens(call.function.name);
|
|
204
|
+
total += this.estimateTokens(call.function.arguments);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return total;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Enforce context window limits by summarizing or truncating
|
|
213
|
+
*/
|
|
214
|
+
enforceContextLimits() {
|
|
215
|
+
const currentTokens = this.getTotalTokens();
|
|
216
|
+
|
|
217
|
+
// If we're approaching the limit (90% capacity)
|
|
218
|
+
if (currentTokens > this.contextWindowSize * 0.9) {
|
|
219
|
+
consoleStyler.log('system', `⚠️ Context limit approaching (${currentTokens}/${this.contextWindowSize} tokens). Optimizing history...`);
|
|
220
|
+
|
|
221
|
+
// Calculate how many tokens we need to free up (aim for 70% capacity)
|
|
222
|
+
const targetTokens = Math.floor(this.contextWindowSize * 0.7);
|
|
223
|
+
|
|
224
|
+
// Simple strategy: Remove oldest exchanges (after system prompt)
|
|
225
|
+
// A smarter strategy would be to summarize, but that requires an LLM call
|
|
226
|
+
|
|
227
|
+
let attempts = 0;
|
|
228
|
+
const maxAttempts = 20; // Prevent infinite loops
|
|
229
|
+
|
|
230
|
+
while (this.getTotalTokens() > targetTokens && this.history.length > 2 && attempts < maxAttempts) {
|
|
231
|
+
// Remove the oldest exchange (index 1 is usually the first user message)
|
|
232
|
+
// We use deleteHistoryExchanges logic but target specific indices
|
|
233
|
+
|
|
234
|
+
// Find first user message after system prompt
|
|
235
|
+
let firstUserIndex = -1;
|
|
236
|
+
for (let i = 1; i < this.history.length; i++) {
|
|
237
|
+
if (this.history[i].role === 'user') {
|
|
238
|
+
firstUserIndex = i;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (firstUserIndex === -1) break; // No user messages found
|
|
244
|
+
|
|
245
|
+
// Find the next user message to define the exchange boundary
|
|
246
|
+
let nextUserIndex = -1;
|
|
247
|
+
for (let i = firstUserIndex + 1; i < this.history.length; i++) {
|
|
248
|
+
if (this.history[i].role === 'user') {
|
|
249
|
+
nextUserIndex = i;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// If no next user message, we're at the last exchange - don't delete recent context unless critical
|
|
255
|
+
if (nextUserIndex === -1 && currentTokens < this.contextWindowSize) {
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Delete everything from firstUserIndex up to (but not including) nextUserIndex
|
|
260
|
+
// If nextUserIndex is -1, delete until end (only if we are critically over limit)
|
|
261
|
+
const deleteCount = (nextUserIndex !== -1 ? nextUserIndex : this.history.length) - firstUserIndex;
|
|
262
|
+
|
|
263
|
+
this.history.splice(firstUserIndex, deleteCount);
|
|
264
|
+
attempts++;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
consoleStyler.log('system', `✓ History optimized. New token count: ~${this.getTotalTokens()}`);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get context statistics
|
|
273
|
+
* @returns {Object}
|
|
274
|
+
*/
|
|
275
|
+
getStats() {
|
|
276
|
+
return {
|
|
277
|
+
messageCount: this.history.length,
|
|
278
|
+
estimatedTokens: this.getTotalTokens(),
|
|
279
|
+
contextWindowSize: this.contextWindowSize,
|
|
280
|
+
utilizationPercent: Math.round((this.getTotalTokens() / this.contextWindowSize) * 100)
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* Save history to a file
|
|
286
|
+
* @param {string} filePath
|
|
287
|
+
* @returns {Promise<boolean>}
|
|
288
|
+
*/
|
|
289
|
+
async save(filePath) {
|
|
290
|
+
try {
|
|
291
|
+
const fs = await import('fs');
|
|
292
|
+
const data = {
|
|
293
|
+
timestamp: new Date().toISOString(),
|
|
294
|
+
history: this.history,
|
|
295
|
+
systemMessage: this.systemMessage
|
|
296
|
+
};
|
|
297
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
298
|
+
return true;
|
|
299
|
+
} catch (error) {
|
|
300
|
+
consoleStyler.log('error', `Failed to save history: ${error.message}`);
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Load history from a file
|
|
307
|
+
* @param {string} filePath
|
|
308
|
+
* @returns {Promise<boolean>}
|
|
309
|
+
*/
|
|
310
|
+
async load(filePath) {
|
|
311
|
+
try {
|
|
312
|
+
const fs = await import('fs');
|
|
313
|
+
if (!fs.existsSync(filePath)) {
|
|
314
|
+
return false;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
318
|
+
|
|
319
|
+
if (data.history && Array.isArray(data.history)) {
|
|
320
|
+
this.history = data.history;
|
|
321
|
+
this.systemMessage = data.systemMessage || this.history.find(msg => msg.role === 'system');
|
|
322
|
+
return true;
|
|
323
|
+
}
|
|
324
|
+
return false;
|
|
325
|
+
} catch (error) {
|
|
326
|
+
consoleStyler.log('error', `Failed to load history: ${error.message}`);
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// System prompt generation
|
|
2
|
+
// Creates the system prompt with workspace context and guidelines
|
|
3
|
+
|
|
4
|
+
export function createSystemPrompt(workingDir, workspace = null, manifestContent = null) {
|
|
5
|
+
let prompt = `You are a JavaScript/Node.js command executor. Your output consists of direct commands and concise results, not explanations.
|
|
6
|
+
|
|
7
|
+
**Working Directory:** ${workingDir}
|
|
8
|
+
The user is executing commands from this directory. When working with files or paths, consider this as the current working directory unless otherwise specified.`;
|
|
9
|
+
|
|
10
|
+
// Add Living Manifest if available
|
|
11
|
+
if (manifestContent) {
|
|
12
|
+
prompt += `
|
|
13
|
+
|
|
14
|
+
**LIVING MANIFEST (SYSTEM_MAP.md):**
|
|
15
|
+
The following is the authoritative state of the system. You MUST adhere to Global Invariants and respect Feature Locks.
|
|
16
|
+
|
|
17
|
+
${manifestContent}
|
|
18
|
+
|
|
19
|
+
**STRUCTURED DEVELOPMENT RULES:**
|
|
20
|
+
1. Check "Global Invariants" before writing any code.
|
|
21
|
+
2. Check "Feature Registry" to see if a feature is Locked.
|
|
22
|
+
- If "Interface" lock is active, you CANNOT change API signatures without a refactor request.
|
|
23
|
+
- If "None" or "Discovery", you are free to design.
|
|
24
|
+
3. Update the manifest using the provided tools as you progress through phases (Discovery -> Interface -> Implementation).
|
|
25
|
+
`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// Add workspace context if active
|
|
29
|
+
if (workspace) {
|
|
30
|
+
prompt += `
|
|
31
|
+
|
|
32
|
+
**ACTIVE WORKSPACE:**
|
|
33
|
+
• Task Goal: ${workspace.task_goal}
|
|
34
|
+
• Current Step: ${workspace.current_step}
|
|
35
|
+
• Status: ${workspace.status}
|
|
36
|
+
• Progress Data: ${JSON.stringify(workspace.progress_data)}
|
|
37
|
+
• Next Steps: ${workspace.next_steps.join(', ')}
|
|
38
|
+
|
|
39
|
+
IMPORTANT: You are continuing work on the above task. Use the workspace context to maintain continuity. Update the workspace as you make progress using the manage_workspace tool.`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
prompt += `
|
|
43
|
+
|
|
44
|
+
**Core Principles:**
|
|
45
|
+
* **Truthfulness:** Be strictly truthful. Never fabricate outcomes, always report failures accurately, and admit when you cannot complete a task.
|
|
46
|
+
* **Language:** Default to modern ES6+ JavaScript and \`async/await\`. Interpret requests to "create" or "build" as "write JavaScript code."
|
|
47
|
+
* **Workspace Management:** For complex multi-step tasks, use the \`manage_workspace\` tool to maintain context across retries and quality evaluations.
|
|
48
|
+
* **Work Reporting:** ALWAYS include a \`workPerformed\` field in your responses when you perform any action or use tools. This should be a brief, clear statement like "I executed JavaScript code to fetch data from the API" or "I created a file with the requested content". This helps users understand what work was completed.
|
|
49
|
+
|
|
50
|
+
Before answering, work through the request step-by-step:
|
|
51
|
+
|
|
52
|
+
1. UNDERSTAND: What is the core question being asked?
|
|
53
|
+
2. ANALYZE: What are the key factors/components involved?
|
|
54
|
+
3. REASON: What logical connections can I make?
|
|
55
|
+
4. SYNTHESIZE: How do these elements combine?
|
|
56
|
+
5. CONCLUDE: What is the most accurate/helpful response?
|
|
57
|
+
|
|
58
|
+
Then provide your answer.
|
|
59
|
+
|
|
60
|
+
**Execution Protocol:**
|
|
61
|
+
1. **Plan:** Analyze the request and formulate a step-by-step technical plan. For complex tasks, create a workspace to track progress.
|
|
62
|
+
2. **Execute:** Carry out the plan using your available tools. Update workspace as you progress.
|
|
63
|
+
3. **Recover:** On error, use your \`analyze_and_recover\` tool to find an alternative solution before giving up.
|
|
64
|
+
4. **Report:** State the final, factual result. Update workspace status when task is complete.
|
|
65
|
+
|
|
66
|
+
**Technical Constraints:**
|
|
67
|
+
* For Node.js v18 compatibility, prefer built-in modules (\`fetch\`) over packages with known issues (\`axios\`, \`undici\`).
|
|
68
|
+
* If a primary tool like \`cheerio\` fails, use a fallback like regex or built-in DOM parsing.
|
|
69
|
+
|
|
70
|
+
**Node.js v18 Compatibility Guidelines:**
|
|
71
|
+
* ALWAYS use built-in fetch instead of axios for HTTP requests
|
|
72
|
+
* For web scraping: Use regex patterns or built-in string methods instead of cheerio
|
|
73
|
+
* Avoid these packages: axios, undici, node-fetch, cheerio (they have File API issues in Node v18)
|
|
74
|
+
* When scraping HTML, use patterns like: /<h[1-6][^>]*>(.*?)<\/h[1-6]>/gi for headlines
|
|
75
|
+
* For complex HTML parsing, use built-in DOMParser alternatives or regex
|
|
76
|
+
|
|
77
|
+
Execute commands. Report results. Recover from errors. Move to next step.`;
|
|
78
|
+
|
|
79
|
+
return prompt;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Create enhanced system prompt with work reporting instruction
|
|
83
|
+
export function createEnhancedSystemPrompt(workingDir, workspace = null) {
|
|
84
|
+
const basePrompt = createSystemPrompt(workingDir, workspace);
|
|
85
|
+
|
|
86
|
+
return basePrompt + `
|
|
87
|
+
|
|
88
|
+
**IMPORTANT RESPONSE FORMAT:**
|
|
89
|
+
Always structure your responses to include actionable information and clear work reporting. When you use tools or execute code, explicitly state what was accomplished in a \`workPerformed\` field or section.`;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Create system prompt for quality evaluation
|
|
93
|
+
export function createQualityEvaluationPrompt() {
|
|
94
|
+
return `You are an AI response quality evaluator. Your job is to objectively assess whether AI responses appropriately address user queries.
|
|
95
|
+
|
|
96
|
+
**Evaluation Criteria:**
|
|
97
|
+
- **Completeness:** Does the response fully address all parts of the user's request?
|
|
98
|
+
- **Accuracy:** Is the information provided correct and factual?
|
|
99
|
+
- **Usefulness:** Does the response provide practical value to the user?
|
|
100
|
+
- **Tool Usage:** If tools were used, were they appropriate and effective?
|
|
101
|
+
- **Clarity:** Is the response clear and well-structured?
|
|
102
|
+
|
|
103
|
+
**Scoring Scale:**
|
|
104
|
+
- 9-10: Excellent response that exceeds expectations
|
|
105
|
+
- 7-8: Good response that meets expectations well
|
|
106
|
+
- 5-6: Adequate response with minor issues
|
|
107
|
+
- 3-4: Poor response with significant problems
|
|
108
|
+
- 1-2: Completely inadequate response
|
|
109
|
+
|
|
110
|
+
**Important:** Consider BOTH the text response AND any tools that were executed. A brief text response paired with successful tool execution that accomplishes the user's goal should be rated highly.`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Create system prompt for tool generation
|
|
114
|
+
export function createToolGenerationPrompt() {
|
|
115
|
+
return `You are a JavaScript function generator. Your job is to convert code snippets into reusable, parameterized functions.
|
|
116
|
+
|
|
117
|
+
**Requirements:**
|
|
118
|
+
1. Extract hardcoded values as function parameters
|
|
119
|
+
2. Add comprehensive error handling
|
|
120
|
+
3. Include detailed JSDoc comments
|
|
121
|
+
4. Return meaningful data structures
|
|
122
|
+
5. Handle edge cases and validation
|
|
123
|
+
6. Use modern ES6+ syntax with async/await
|
|
124
|
+
7. Make functions self-contained
|
|
125
|
+
|
|
126
|
+
**Output:** Return ONLY the function code, no explanations or markdown formatting.`;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Create system prompt for schema generation
|
|
130
|
+
export function createSchemaGenerationPrompt() {
|
|
131
|
+
return `You are a JSON schema generator for OpenAI function calling format.
|
|
132
|
+
|
|
133
|
+
**Requirements:**
|
|
134
|
+
1. Analyze function parameters and their types
|
|
135
|
+
2. Provide clear descriptions for each parameter
|
|
136
|
+
3. Identify required vs optional parameters
|
|
137
|
+
4. Use proper JSON schema types and formats
|
|
138
|
+
5. Follow OpenAI function calling specification
|
|
139
|
+
|
|
140
|
+
**Output:** Return ONLY the JSON schema object, no explanations or markdown formatting.`;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Get appropriate system prompt based on context
|
|
144
|
+
export function getSystemPrompt(context = {}) {
|
|
145
|
+
const {
|
|
146
|
+
type = 'default',
|
|
147
|
+
workingDir = process.cwd(),
|
|
148
|
+
workspace = null,
|
|
149
|
+
manifestContent = null,
|
|
150
|
+
enhanced = false
|
|
151
|
+
} = context;
|
|
152
|
+
|
|
153
|
+
switch (type) {
|
|
154
|
+
case 'quality':
|
|
155
|
+
return createQualityEvaluationPrompt();
|
|
156
|
+
|
|
157
|
+
case 'tool-generation':
|
|
158
|
+
return createToolGenerationPrompt();
|
|
159
|
+
|
|
160
|
+
case 'schema-generation':
|
|
161
|
+
return createSchemaGenerationPrompt();
|
|
162
|
+
|
|
163
|
+
case 'enhanced':
|
|
164
|
+
return createEnhancedSystemPrompt(workingDir, workspace);
|
|
165
|
+
|
|
166
|
+
default:
|
|
167
|
+
return enhanced
|
|
168
|
+
? createEnhancedSystemPrompt(workingDir, workspace)
|
|
169
|
+
: createSystemPrompt(workingDir, workspace, manifestContent);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Add work performed instruction to existing messages
|
|
174
|
+
export function enhanceMessagesWithWorkReporting(messages) {
|
|
175
|
+
if (messages.length > 1) {
|
|
176
|
+
const lastUserMessage = messages[messages.length - 1];
|
|
177
|
+
if (lastUserMessage.role === 'user') {
|
|
178
|
+
lastUserMessage.content += `\n\nIMPORTANT: Please include a 'workPerformed' field in your response with a brief summary of any work completed (e.g., "I executed JavaScript code to analyze the data" or "I created a file with the requested content").`;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return messages;
|
|
182
|
+
}
|