feat: implement context file loading system for agent prompts

- Introduced a new utility function `loadContextFiles` to load project-specific context files from the `.automaker/context/` directory, enhancing agent prompts with project rules and guidelines.
- Updated `AgentService` and `AutoModeService` to utilize the new context loading functionality, combining context prompts with existing system prompts for improved agent performance.
- Added comprehensive documentation on the context files system, including usage examples and metadata structure, to facilitate better understanding and implementation.
- Removed redundant context loading logic from `AutoModeService`, streamlining the codebase.

These changes aim to improve the agent's contextual awareness and adherence to project-specific conventions.
This commit is contained in:
Test User
2025-12-22 00:09:57 -05:00
parent e2718b37e3
commit 398f7b8fdd
5 changed files with 462 additions and 81 deletions

View File

@@ -7,7 +7,12 @@ import path from 'path';
import * as secureFs from '../lib/secure-fs.js';
import type { EventEmitter } from '../lib/events.js';
import type { ExecuteOptions } from '@automaker/types';
import { readImageAsBase64, buildPromptWithImages, isAbortError } from '@automaker/utils';
import {
readImageAsBase64,
buildPromptWithImages,
isAbortError,
loadContextFiles,
} from '@automaker/utils';
import { ProviderFactory } from '../providers/provider-factory.js';
import { createChatOptions, validateWorkingDirectory } from '../lib/sdk-options.js';
import { PathNotAllowedError } from '@automaker/platform';
@@ -178,12 +183,27 @@ export class AgentService {
await this.saveSession(sessionId, session.messages);
try {
// Determine the effective working directory for context loading
const effectiveWorkDir = workingDirectory || session.workingDirectory;
// Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.)
const { formattedPrompt: contextFilesPrompt } = await loadContextFiles({
projectPath: effectiveWorkDir,
fsModule: secureFs as Parameters<typeof loadContextFiles>[0]['fsModule'],
});
// Build combined system prompt with base prompt and context files
const baseSystemPrompt = this.getSystemPrompt();
const combinedSystemPrompt = contextFilesPrompt
? `${contextFilesPrompt}\n\n${baseSystemPrompt}`
: baseSystemPrompt;
// Build SDK options using centralized configuration
const sdkOptions = createChatOptions({
cwd: workingDirectory || session.workingDirectory,
cwd: effectiveWorkDir,
model: model,
sessionModel: session.model,
systemPrompt: this.getSystemPrompt(),
systemPrompt: combinedSystemPrompt,
abortController: session.abortController!,
});
@@ -203,8 +223,8 @@ export class AgentService {
const options: ExecuteOptions = {
prompt: '', // Will be set below based on images
model: effectiveModel,
cwd: workingDirectory || session.workingDirectory,
systemPrompt: this.getSystemPrompt(),
cwd: effectiveWorkDir,
systemPrompt: combinedSystemPrompt,
maxTurns: maxTurns,
allowedTools: allowedTools,
abortController: session.abortController!,

View File

@@ -11,10 +11,15 @@
import { ProviderFactory } from '../providers/provider-factory.js';
import type { ExecuteOptions, Feature } from '@automaker/types';
import { buildPromptWithImages, isAbortError, classifyError } from '@automaker/utils';
import {
buildPromptWithImages,
isAbortError,
classifyError,
loadContextFiles,
} from '@automaker/utils';
import { resolveModelString, DEFAULT_MODELS } from '@automaker/model-resolver';
import { resolveDependencies, areDependenciesSatisfied } from '@automaker/dependency-resolver';
import { getFeatureDir, getAutomakerDir, getFeaturesDir, getContextDir } from '@automaker/platform';
import { getFeatureDir, getAutomakerDir, getFeaturesDir } from '@automaker/platform';
import { exec } from 'child_process';
import { promisify } from 'util';
import path from 'path';
@@ -549,7 +554,10 @@ export class AutoModeService {
// Build the prompt - use continuation prompt if provided (for recovery after plan approval)
let prompt: string;
// Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) - passed as system prompt
const contextFiles = await this.loadContextFiles(projectPath);
const { formattedPrompt: contextFilesPrompt } = await loadContextFiles({
projectPath,
fsModule: secureFs as Parameters<typeof loadContextFiles>[0]['fsModule'],
});
if (options?.continuationPrompt) {
// Continuation prompt is used when recovering from a plan approval
@@ -595,7 +603,7 @@ export class AutoModeService {
projectPath,
planningMode: feature.planningMode,
requirePlanApproval: feature.requirePlanApproval,
systemPrompt: contextFiles || undefined,
systemPrompt: contextFilesPrompt || undefined,
}
);
@@ -736,7 +744,10 @@ export class AutoModeService {
}
// Load project context files (CLAUDE.md, CODE_QUALITY.md, etc.) - passed as system prompt
const contextFiles = await this.loadContextFiles(projectPath);
const { formattedPrompt: contextFilesPrompt } = await loadContextFiles({
projectPath,
fsModule: secureFs as Parameters<typeof loadContextFiles>[0]['fsModule'],
});
// Build complete prompt with feature info, previous context, and follow-up instructions
let fullPrompt = `## Follow-up on Feature Implementation
@@ -864,7 +875,7 @@ Address the follow-up instructions above. Review the previous work and make the
projectPath,
planningMode: 'skip', // Follow-ups don't require approval
previousContent: previousContext || undefined,
systemPrompt: contextFiles || undefined,
systemPrompt: contextFilesPrompt || undefined,
}
);
@@ -1044,63 +1055,6 @@ Address the follow-up instructions above. Review the previous work and make the
}
}
/**
* Load context files from .automaker/context/ directory
* These are user-defined context files (CLAUDE.md, CODE_QUALITY.md, etc.)
* that provide project-specific rules and guidelines for the agent.
*/
private async loadContextFiles(projectPath: string): Promise<string> {
// Use path.resolve for cross-platform absolute path handling
const contextDir = path.resolve(getContextDir(projectPath));
try {
// Check if directory exists first
await secureFs.access(contextDir);
const files = await secureFs.readdir(contextDir);
// Filter for text-based context files (case-insensitive for Windows)
const textFiles = files.filter((f) => {
const lower = f.toLowerCase();
return lower.endsWith('.md') || lower.endsWith('.txt');
});
if (textFiles.length === 0) return '';
const contents: string[] = [];
for (const file of textFiles) {
// Use path.join for cross-platform path construction
const filePath = path.join(contextDir, file);
const content = (await secureFs.readFile(filePath, 'utf-8')) as string;
contents.push(`## ${file}\n\n${content}`);
}
console.log(`[AutoMode] Loaded ${textFiles.length} context file(s): ${textFiles.join(', ')}`);
return `# ⚠️ CRITICAL: Project Context Files - READ AND FOLLOW STRICTLY
**IMPORTANT**: The following context files contain MANDATORY project-specific rules and conventions. You MUST:
1. Read these rules carefully before taking any action
2. Follow ALL commands exactly as shown (e.g., if the project uses \`pnpm\`, NEVER use \`npm\` or \`npx\`)
3. Follow ALL coding conventions, commit message formats, and architectural patterns specified
4. Reference these rules before running ANY shell commands or making commits
Failure to follow these rules will result in broken builds, failed CI, and rejected commits.
${contents.join('\n\n---\n\n')}
---
**REMINDER**: Before running any command, verify you are using the correct package manager and following the conventions above.
---
`;
} catch {
// Context directory doesn't exist or is empty - this is fine
return '';
}
}
/**
* Analyze project to gather context
*/