Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions src/core/prompts/sections/__tests__/custom-instructions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,128 @@ describe("addCustomInstructions", () => {
expect(result).toContain("Rules from .roorules-test-mode:\nmode specific rules")
})

it("should load AGENTS.md when useAgentRules is true", async () => {
// Simulate no .roo/rules-test-mode directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })

readFileMock.mockImplementation((filePath: PathLike) => {
const pathStr = filePath.toString()
if (pathStr.endsWith("AGENTS.md")) {
return Promise.resolve("Agent rules from AGENTS.md file")
}
return Promise.reject({ code: "ENOENT" })
})

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{ useAgentRules: true },
)

expect(result).toContain("# Agent Rules Standard (AGENTS.md):")
expect(result).toContain("Agent rules from AGENTS.md file")
expect(readFileMock).toHaveBeenCalledWith(expect.stringContaining("AGENTS.md"), "utf-8")
})

it("should not load AGENTS.md when useAgentRules is false", async () => {
// Simulate no .roo/rules-test-mode directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })

readFileMock.mockImplementation((filePath: PathLike) => {
const pathStr = filePath.toString()
if (pathStr.endsWith("AGENTS.md")) {
return Promise.resolve("Agent rules from AGENTS.md file")
}
return Promise.reject({ code: "ENOENT" })
})

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{ useAgentRules: false },
)

expect(result).not.toContain("# Agent Rules Standard (AGENTS.md):")
expect(result).not.toContain("Agent rules from AGENTS.md file")
})

it("should not load AGENTS.md by default when useAgentRules is undefined", async () => {
// Simulate no .roo/rules-test-mode directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })

readFileMock.mockImplementation((filePath: PathLike) => {
const pathStr = filePath.toString()
if (pathStr.endsWith("AGENTS.md")) {
return Promise.resolve("Agent rules from AGENTS.md file")
}
return Promise.reject({ code: "ENOENT" })
})

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{}, // No useAgentRules specified
)

expect(result).not.toContain("# Agent Rules Standard (AGENTS.md):")
expect(result).not.toContain("Agent rules from AGENTS.md file")
})

it("should handle missing AGENTS.md gracefully", async () => {
// Simulate no .roo/rules-test-mode directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })

readFileMock.mockRejectedValue({ code: "ENOENT" })

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{ useAgentRules: true },
)

expect(result).toContain("Global Instructions:\nglobal instructions")
expect(result).toContain("Mode-specific Instructions:\nmode instructions")
expect(result).not.toContain("# Agent Rules Standard (AGENTS.md):")
})

it("should include AGENTS.md content along with other rules", async () => {
// Simulate no .roo/rules-test-mode directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })

readFileMock.mockImplementation((filePath: PathLike) => {
const pathStr = filePath.toString()
if (pathStr.endsWith("AGENTS.md")) {
return Promise.resolve("Agent rules content")
}
if (pathStr.endsWith(".roorules")) {
return Promise.resolve("Roo rules content")
}
return Promise.reject({ code: "ENOENT" })
})

const result = await addCustomInstructions(
"mode instructions",
"global instructions",
"/fake/path",
"test-mode",
{ useAgentRules: true },
)

// Should contain both AGENTS.md and .roorules content
expect(result).toContain("# Agent Rules Standard (AGENTS.md):")
expect(result).toContain("Agent rules content")
expect(result).toContain("# Rules from .roorules:")
expect(result).toContain("Roo rules content")
})

it("should return empty string when no instructions provided", async () => {
// Simulate no .roo/rules directory
statMock.mockRejectedValueOnce({ code: "ENOENT" })
Expand Down
31 changes: 30 additions & 1 deletion src/core/prompts/sections/custom-instructions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,33 @@ export async function loadRuleFiles(cwd: string): Promise<string> {
return ""
}

/**
* Load AGENTS.md file from the project root if it exists
*/
async function loadAgentRulesFile(cwd: string): Promise<string> {
try {
const agentsPath = path.join(cwd, "AGENTS.md")
const content = await safeReadFile(agentsPath)
if (content) {
return `# Agent Rules Standard (AGENTS.md):\n${content}`
}
} catch (err) {
// Silently ignore errors - AGENTS.md is optional
}
return ""
}

export async function addCustomInstructions(
modeCustomInstructions: string,
globalCustomInstructions: string,
cwd: string,
mode: string,
options: { language?: string; rooIgnoreInstructions?: string; settings?: Record<string, any> } = {},
options: {
language?: string
rooIgnoreInstructions?: string
useAgentRules?: boolean
settings?: Record<string, any>
} = {},
): Promise<string> {
const sections = []

Expand Down Expand Up @@ -297,6 +318,14 @@ export async function addCustomInstructions(
rules.push(options.rooIgnoreInstructions)
}

// Add AGENTS.md content if enabled (default: false)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition for including AGENTS.md has been changed from options.useAgentRules !== false to options.useAgentRules === true, and the comment now says "default: false". This conflicts with the PR description which states the default should be true. Please clarify and align the default behavior (and documentation) for useAgentRules.

if (options.useAgentRules === true) {
const agentRulesContent = await loadAgentRulesFile(cwd)
if (agentRulesContent && agentRulesContent.trim()) {
rules.push(agentRulesContent.trim())
}
}

// Add generic rules
const genericRuleContent = await loadRuleFiles(cwd)
if (genericRuleContent && genericRuleContent.trim()) {
Expand Down
14 changes: 12 additions & 2 deletions src/core/prompts/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,12 @@ ${getSystemInfoSection(cwd)}

${getObjectiveSection(codeIndexManager, experiments)}

${await addCustomInstructions(baseInstructions, globalCustomInstructions || "", cwd, mode, { language: language ?? formatLanguage(vscode.env.language), rooIgnoreInstructions, settings })}`
${await addCustomInstructions(baseInstructions, globalCustomInstructions || "", cwd, mode, {
language: language ?? formatLanguage(vscode.env.language),
rooIgnoreInstructions,
useAgentRules: settings?.useAgentRules,
settings,
})}`

return basePrompt
}
Expand Down Expand Up @@ -177,7 +182,12 @@ export const SYSTEM_PROMPT = async (
globalCustomInstructions || "",
cwd,
mode,
{ language: language ?? formatLanguage(vscode.env.language), rooIgnoreInstructions, settings },
{
language: language ?? formatLanguage(vscode.env.language),
rooIgnoreInstructions,
useAgentRules: settings?.useAgentRules,
settings,
},
)

// For file-based prompts, don't include the tool sections
Expand Down
1 change: 1 addition & 0 deletions src/core/protect/RooProtectedController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class RooProtectedController {
".roo/**",
".vscode/**",
".rooprotected", // For future use
"AGENTS.md",
]

constructor(cwd: string) {
Expand Down
5 changes: 5 additions & 0 deletions src/core/protect/__tests__/RooProtectedController.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ describe("RooProtectedController", () => {
expect(controller.isWriteProtected(".vscode/tasks.json")).toBe(true)
})

it("should protect AGENTS.md file", () => {
expect(controller.isWriteProtected("AGENTS.md")).toBe(true)
})

it("should not protect other files starting with .roo", () => {
expect(controller.isWriteProtected(".roosettings")).toBe(false)
expect(controller.isWriteProtected(".rooconfig")).toBe(false)
Expand Down Expand Up @@ -142,6 +146,7 @@ describe("RooProtectedController", () => {
".roo/**",
".vscode/**",
".rooprotected",
"AGENTS.md",
])
})
})
Expand Down
3 changes: 3 additions & 0 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as path from "path"
import * as vscode from "vscode"
import os from "os"
import crypto from "crypto"
import EventEmitter from "events"
Expand Down Expand Up @@ -1662,6 +1663,8 @@ export class Task extends EventEmitter<ClineEvents> {
{
maxConcurrentFileReads,
todoListEnabled: apiConfiguration?.todoListEnabled,
useAgentRules:
vscode.workspace.getConfiguration("roo-cline").get<boolean>("useAgentRules") ?? false,
},
)
})()
Expand Down
5 changes: 5 additions & 0 deletions src/core/webview/generateSystemPrompt.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as vscode from "vscode"
import { WebviewMessage } from "../../shared/WebviewMessage"
import { defaultModeSlug, getModeBySlug, getGroupName } from "../../shared/modes"
import { buildApiHandler } from "../../api"
Expand Down Expand Up @@ -82,6 +83,10 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
maxReadFileLine !== -1,
{
maxConcurrentFileReads,
useAgentRules:
provider.context.globalState.get("useAgentRules") ??
vscode.workspace.getConfiguration("roo-cline").get<boolean>("useAgentRules") ??
false,
},
)

Expand Down
5 changes: 5 additions & 0 deletions src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,11 @@
"type": "string",
"default": "",
"description": "%settings.autoImportSettingsPath.description%"
},
"roo-cline.useAgentRules": {
"type": "boolean",
"default": false,
"description": "%settings.useAgentRules.description%"
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/package.nls.ca.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "La família del model de llenguatge (p. ex. gpt-4)",
"settings.customStoragePath.description": "Ruta d'emmagatzematge personalitzada. Deixeu-la buida per utilitzar la ubicació predeterminada. Admet rutes absolutes (p. ex. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Habilitar correccions ràpides de Roo Code.",
"settings.autoImportSettingsPath.description": "Ruta a un fitxer de configuració de RooCode per importar automàticament en iniciar l'extensió. Admet rutes absolutes i rutes relatives al directori d'inici (per exemple, '~/Documents/roo-code-settings.json'). Deixeu-ho en blanc per desactivar la importació automàtica."
"settings.autoImportSettingsPath.description": "Ruta a un fitxer de configuració de RooCode per importar automàticament en iniciar l'extensió. Admet rutes absolutes i rutes relatives al directori d'inici (per exemple, '~/Documents/roo-code-settings.json'). Deixeu-ho en blanc per desactivar la importació automàtica.",
"settings.useAgentRules.description": "Activa la càrrega de fitxers AGENTS.md per a regles específiques de l'agent (vegeu https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.de.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "Die Familie des Sprachmodells (z.B. gpt-4)",
"settings.customStoragePath.description": "Benutzerdefinierter Speicherpfad. Leer lassen, um den Standardspeicherort zu verwenden. Unterstützt absolute Pfade (z.B. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Roo Code Schnelle Problembehebung aktivieren.",
"settings.autoImportSettingsPath.description": "Pfad zu einer RooCode-Konfigurationsdatei, die beim Start der Erweiterung automatisch importiert wird. Unterstützt absolute Pfade und Pfade relativ zum Home-Verzeichnis (z.B. '~/Documents/roo-code-settings.json'). Leer lassen, um den automatischen Import zu deaktivieren."
"settings.autoImportSettingsPath.description": "Pfad zu einer RooCode-Konfigurationsdatei, die beim Start der Erweiterung automatisch importiert wird. Unterstützt absolute Pfade und Pfade relativ zum Home-Verzeichnis (z.B. '~/Documents/roo-code-settings.json'). Leer lassen, um den automatischen Import zu deaktivieren.",
"settings.useAgentRules.description": "Aktiviert das Laden von AGENTS.md-Dateien für agentenspezifische Regeln (siehe https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.es.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "La familia del modelo de lenguaje (ej. gpt-4)",
"settings.customStoragePath.description": "Ruta de almacenamiento personalizada. Dejar vacío para usar la ubicación predeterminada. Admite rutas absolutas (ej. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Habilitar correcciones rápidas de Roo Code.",
"settings.autoImportSettingsPath.description": "Ruta a un archivo de configuración de RooCode para importar automáticamente al iniciar la extensión. Admite rutas absolutas y rutas relativas al directorio de inicio (por ejemplo, '~/Documents/roo-code-settings.json'). Dejar vacío para desactivar la importación automática."
"settings.autoImportSettingsPath.description": "Ruta a un archivo de configuración de RooCode para importar automáticamente al iniciar la extensión. Admite rutas absolutas y rutas relativas al directorio de inicio (por ejemplo, '~/Documents/roo-code-settings.json'). Dejar vacío para desactivar la importación automática.",
"settings.useAgentRules.description": "Habilita la carga de archivos AGENTS.md para reglas específicas del agente (ver https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "La famille du modèle de langage (ex: gpt-4)",
"settings.customStoragePath.description": "Chemin de stockage personnalisé. Laisser vide pour utiliser l'emplacement par défaut. Prend en charge les chemins absolus (ex: 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Activer les correctifs rapides de Roo Code.",
"settings.autoImportSettingsPath.description": "Chemin d'accès à un fichier de configuration RooCode à importer automatiquement au démarrage de l'extension. Prend en charge les chemins absolus et les chemins relatifs au répertoire de base (par exemple, '~/Documents/roo-code-settings.json'). Laisser vide pour désactiver l'importation automatique."
"settings.autoImportSettingsPath.description": "Chemin d'accès à un fichier de configuration RooCode à importer automatiquement au démarrage de l'extension. Prend en charge les chemins absolus et les chemins relatifs au répertoire de base (par exemple, '~/Documents/roo-code-settings.json'). Laisser vide pour désactiver l'importation automatique.",
"settings.useAgentRules.description": "Active le chargement des fichiers AGENTS.md pour les règles spécifiques à l'agent (voir https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.hi.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "भाषा मॉडल का परिवार (उदा. gpt-4)",
"settings.customStoragePath.description": "कस्टम स्टोरेज पाथ। डिफ़ॉल्ट स्थान का उपयोग करने के लिए खाली छोड़ें। पूर्ण पथ का समर्थन करता है (उदा. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Roo Code त्वरित सुधार सक्षम करें",
"settings.autoImportSettingsPath.description": "RooCode कॉन्फ़िगरेशन फ़ाइल का पथ जिसे एक्सटेंशन स्टार्टअप पर स्वचालित रूप से आयात किया जाएगा। होम डायरेक्टरी के सापेक्ष पूर्ण पथ और पथों का समर्थन करता है (उदाहरण के लिए '~/Documents/roo-code-settings.json')। ऑटो-इंपोर्ट को अक्षम करने के लिए खाली छोड़ दें।"
"settings.autoImportSettingsPath.description": "RooCode कॉन्फ़िगरेशन फ़ाइल का पथ जिसे एक्सटेंशन स्टार्टअप पर स्वचालित रूप से आयात किया जाएगा। होम डायरेक्टरी के सापेक्ष पूर्ण पथ और पथों का समर्थन करता है (उदाहरण के लिए '~/Documents/roo-code-settings.json')। ऑटो-इंपोर्ट को अक्षम करने के लिए खाली छोड़ दें।",
"settings.useAgentRules.description": "एजेंट-विशिष्ट नियमों के लिए AGENTS.md फ़ाइलों को लोड करना सक्षम करें (देखें https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.id.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "Keluarga dari model bahasa (misalnya gpt-4)",
"settings.customStoragePath.description": "Path penyimpanan kustom. Biarkan kosong untuk menggunakan lokasi default. Mendukung path absolut (misalnya 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Aktifkan perbaikan cepat Roo Code.",
"settings.autoImportSettingsPath.description": "Path ke file konfigurasi RooCode untuk diimpor secara otomatis saat ekstensi dimulai. Mendukung path absolut dan path relatif terhadap direktori home (misalnya '~/Documents/roo-code-settings.json'). Biarkan kosong untuk menonaktifkan impor otomatis."
"settings.autoImportSettingsPath.description": "Path ke file konfigurasi RooCode untuk diimpor secara otomatis saat ekstensi dimulai. Mendukung path absolut dan path relatif terhadap direktori home (misalnya '~/Documents/roo-code-settings.json'). Biarkan kosong untuk menonaktifkan impor otomatis.",
"settings.useAgentRules.description": "Aktifkan pemuatan file AGENTS.md untuk aturan khusus agen (lihat https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.it.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "La famiglia del modello linguistico (es. gpt-4)",
"settings.customStoragePath.description": "Percorso di archiviazione personalizzato. Lasciare vuoto per utilizzare la posizione predefinita. Supporta percorsi assoluti (es. 'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Abilita correzioni rapide di Roo Code.",
"settings.autoImportSettingsPath.description": "Percorso di un file di configurazione di RooCode da importare automaticamente all'avvio dell'estensione. Supporta percorsi assoluti e percorsi relativi alla directory home (ad es. '~/Documents/roo-code-settings.json'). Lasciare vuoto per disabilitare l'importazione automatica."
"settings.autoImportSettingsPath.description": "Percorso di un file di configurazione di RooCode da importare automaticamente all'avvio dell'estensione. Supporta percorsi assoluti e percorsi relativi alla directory home (ad es. '~/Documents/roo-code-settings.json'). Lasciare vuoto per disabilitare l'importazione automatica.",
"settings.useAgentRules.description": "Abilita il caricamento dei file AGENTS.md per regole specifiche dell'agente (vedi https://agent-rules.org/)"
}
3 changes: 2 additions & 1 deletion src/package.nls.ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,6 @@
"settings.vsCodeLmModelSelector.family.description": "言語モデルのファミリー(例:gpt-4)",
"settings.customStoragePath.description": "カスタムストレージパス。デフォルトの場所を使用する場合は空のままにします。絶対パスをサポートします(例:'D:\\RooCodeStorage')",
"settings.enableCodeActions.description": "Roo Codeのクイック修正を有効にする。",
"settings.autoImportSettingsPath.description": "拡張機能の起動時に自動的にインポートするRooCode設定ファイルへのパス。絶対パスとホームディレクトリからの相対パスをサポートします(例:'~/Documents/roo-code-settings.json')。自動インポートを無効にするには、空のままにします。"
"settings.autoImportSettingsPath.description": "拡張機能の起動時に自動的にインポートするRooCode設定ファイルへのパス。絶対パスとホームディレクトリからの相対パスをサポートします(例:'~/Documents/roo-code-settings.json')。自動インポートを無効にするには、空のままにします。",
"settings.useAgentRules.description": "エージェント固有のルールのためにAGENTS.mdファイルの読み込みを有効にします(参照:https://agent-rules.org/)"
}
Loading