mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: rename smartContextTracking to smartRead and handle @ mentioned files
- Rename experiment ID from smartContextTracking to smartRead - Apply smart read logic to @ file mentions (skip files already in context) - Add parseMentions parameters for experiments and apiConversationHistory - Add English translation keys for SMART_READ experiment - Fix TypeScript errors and update tests
This commit is contained in:
parent
59a8b38203
commit
dbd059f548
10 changed files with 75 additions and 28 deletions
|
|
@ -13,7 +13,7 @@ export const experimentIds = [
|
|||
"imageGeneration",
|
||||
"runSlashCommand",
|
||||
"multipleNativeToolCalls",
|
||||
"smartContextTracking",
|
||||
"smartRead",
|
||||
] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
|
@ -31,7 +31,7 @@ export const experimentsSchema = z.object({
|
|||
imageGeneration: z.boolean().optional(),
|
||||
runSlashCommand: z.boolean().optional(),
|
||||
multipleNativeToolCalls: z.boolean().optional(),
|
||||
smartContextTracking: z.boolean().optional(),
|
||||
smartRead: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type Experiments = z.infer<typeof experimentsSchema>
|
||||
|
|
|
|||
|
|
@ -15,11 +15,14 @@ import { diagnosticsToProblemsString } from "../../integrations/diagnostics"
|
|||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
|
||||
import { FileContextTracker } from "../context-tracking/FileContextTracker"
|
||||
import { checkFileContextStatus, getReReadNotice } from "../context-tracking/FileContextStatusChecker"
|
||||
import type { ApiMessage } from "../task-persistence/apiMessages"
|
||||
|
||||
import { RooIgnoreController } from "../ignore/RooIgnoreController"
|
||||
import { getCommand, type Command } from "../../services/command/commands"
|
||||
|
||||
import { t } from "../../i18n"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
|
||||
function getUrlErrorMessage(error: unknown): string {
|
||||
const errorMessage = error instanceof Error ? error.message : String(error)
|
||||
|
|
@ -81,6 +84,8 @@ export async function parseMentions(
|
|||
includeDiagnosticMessages: boolean = true,
|
||||
maxDiagnosticMessages: number = 50,
|
||||
maxReadFileLine?: number,
|
||||
experimentsConfig?: Record<string, boolean>,
|
||||
apiConversationHistory?: ApiMessage[],
|
||||
): Promise<string> {
|
||||
const mentions: Set<string> = new Set()
|
||||
const validCommands: Map<string, Command> = new Map()
|
||||
|
|
@ -182,6 +187,37 @@ export async function parseMentions(
|
|||
} else if (mention.startsWith("/")) {
|
||||
const mentionPath = mention.slice(1)
|
||||
try {
|
||||
// Check if smart read is enabled and file is already in effective context
|
||||
const isSmartReadEnabled = experiments.isEnabled(experimentsConfig ?? {}, EXPERIMENT_IDS.SMART_READ)
|
||||
|
||||
if (
|
||||
isSmartReadEnabled &&
|
||||
fileContextTracker &&
|
||||
apiConversationHistory &&
|
||||
!mention.endsWith("/") // Only for files, not folders
|
||||
) {
|
||||
const absolutePath = path.resolve(cwd, unescapeSpaces(mentionPath))
|
||||
const taskMetadata = await fileContextTracker.getTaskMetadata(fileContextTracker.taskId)
|
||||
const status = await checkFileContextStatus(
|
||||
mentionPath,
|
||||
absolutePath,
|
||||
taskMetadata,
|
||||
apiConversationHistory,
|
||||
)
|
||||
|
||||
if (!status.shouldReRead) {
|
||||
// File is already in effective context, return notice instead of content
|
||||
const notice = getReReadNotice(status.reason)
|
||||
const noticeText = notice
|
||||
? `(This file's content is already in context. ${notice})`
|
||||
: "(This file's content is already in context and hasn't changed.)"
|
||||
parsedText += `\n\n<file_content path="${mentionPath}">\n${noticeText}\n</file_content>`
|
||||
// Still track the context with the same source
|
||||
await fileContextTracker.trackFileContext(mentionPath, "file_mentioned")
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
const content = await getFileOrFolderContent(
|
||||
mentionPath,
|
||||
cwd,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { Anthropic } from "@anthropic-ai/sdk"
|
|||
import { parseMentions } from "./index"
|
||||
import { UrlContentFetcher } from "../../services/browser/UrlContentFetcher"
|
||||
import { FileContextTracker } from "../context-tracking/FileContextTracker"
|
||||
import type { ApiMessage } from "../task-persistence/apiMessages"
|
||||
|
||||
/**
|
||||
* Process mentions in user content, specifically within task and feedback tags
|
||||
|
|
@ -16,6 +17,8 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages = true,
|
||||
maxDiagnosticMessages = 50,
|
||||
maxReadFileLine,
|
||||
experiments,
|
||||
apiConversationHistory,
|
||||
}: {
|
||||
userContent: Anthropic.Messages.ContentBlockParam[]
|
||||
cwd: string
|
||||
|
|
@ -26,6 +29,8 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages?: boolean
|
||||
maxDiagnosticMessages?: number
|
||||
maxReadFileLine?: number
|
||||
experiments?: Record<string, boolean>
|
||||
apiConversationHistory?: ApiMessage[]
|
||||
}) {
|
||||
// Process userContent array, which contains various block types:
|
||||
// TextBlockParam, ImageBlockParam, ToolUseBlockParam, and ToolResultBlockParam.
|
||||
|
|
@ -59,6 +64,8 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
maxReadFileLine,
|
||||
experiments,
|
||||
apiConversationHistory,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -79,6 +86,8 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
maxReadFileLine,
|
||||
experiments,
|
||||
apiConversationHistory,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
@ -100,6 +109,8 @@ export async function processUserContentMentions({
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
maxReadFileLine,
|
||||
experiments,
|
||||
apiConversationHistory,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2257,12 +2257,12 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
}),
|
||||
)
|
||||
|
||||
const {
|
||||
showRooIgnoredFiles = false,
|
||||
includeDiagnosticMessages = true,
|
||||
maxDiagnosticMessages = 50,
|
||||
maxReadFileLine = -1,
|
||||
} = (await this.providerRef.deref()?.getState()) ?? {}
|
||||
const providerState = await this.providerRef.deref()?.getState()
|
||||
const showRooIgnoredFiles = providerState?.showRooIgnoredFiles ?? false
|
||||
const includeDiagnosticMessages = providerState?.includeDiagnosticMessages ?? true
|
||||
const maxDiagnosticMessages = providerState?.maxDiagnosticMessages ?? 50
|
||||
const maxReadFileLine = providerState?.maxReadFileLine ?? -1
|
||||
const experimentsConfig = providerState?.experiments
|
||||
|
||||
const parsedUserContent = await processUserContentMentions({
|
||||
userContent: currentUserContent,
|
||||
|
|
@ -2274,6 +2274,8 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
|
|||
includeDiagnosticMessages,
|
||||
maxDiagnosticMessages,
|
||||
maxReadFileLine,
|
||||
experiments: experimentsConfig,
|
||||
apiConversationHistory: this.apiConversationHistory,
|
||||
})
|
||||
|
||||
const environmentDetails = await getEnvironmentDetails(this, currentIncludeFileDetails)
|
||||
|
|
|
|||
|
|
@ -147,11 +147,11 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
try {
|
||||
const filesToApprove: FileResult[] = []
|
||||
|
||||
// Check if smart context tracking experiment is enabled
|
||||
// Check if smart read experiment is enabled
|
||||
const experimentState = await task.providerRef.deref()?.getState()
|
||||
const isSmartContextTrackingEnabled = experiments.isEnabled(
|
||||
const isSmartReadEnabled = experiments.isEnabled(
|
||||
experimentState?.experiments ?? {},
|
||||
EXPERIMENT_IDS.SMART_CONTEXT_TRACKING,
|
||||
EXPERIMENT_IDS.SMART_READ,
|
||||
)
|
||||
|
||||
for (const fileResult of fileResults) {
|
||||
|
|
@ -205,10 +205,7 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
|
||||
// Check if file needs to be re-read based on context status (only if experiment enabled)
|
||||
// Skip this check for line range requests as those always need fresh content
|
||||
if (
|
||||
isSmartContextTrackingEnabled &&
|
||||
(!fileResult.lineRanges || fileResult.lineRanges.length === 0)
|
||||
) {
|
||||
if (isSmartReadEnabled && (!fileResult.lineRanges || fileResult.lineRanges.length === 0)) {
|
||||
const metadata = await task.fileContextTracker.getTaskMetadata(task.taskId)
|
||||
const contextStatus = await checkFileContextStatus(
|
||||
relPath,
|
||||
|
|
|
|||
|
|
@ -91,12 +91,9 @@ export async function simpleReadFileTool(
|
|||
return
|
||||
}
|
||||
|
||||
// Check if smart context tracking experiment is enabled
|
||||
// Check if smart read experiment is enabled
|
||||
const state = await cline.providerRef.deref()?.getState()
|
||||
const isSmartContextTrackingEnabled = experiments.isEnabled(
|
||||
state?.experiments ?? {},
|
||||
EXPERIMENT_IDS.SMART_CONTEXT_TRACKING,
|
||||
)
|
||||
const isSmartReadEnabled = experiments.isEnabled(state?.experiments ?? {}, EXPERIMENT_IDS.SMART_READ)
|
||||
|
||||
// Check if file needs to be re-read based on context status (only if experiment enabled)
|
||||
let contextStatus: FileContextStatus = {
|
||||
|
|
@ -105,7 +102,7 @@ export async function simpleReadFileTool(
|
|||
}
|
||||
let reReadNotice: string | undefined = undefined
|
||||
|
||||
if (isSmartContextTrackingEnabled) {
|
||||
if (isSmartReadEnabled) {
|
||||
const metadata = await cline.fileContextTracker.getTaskMetadata(cline.taskId)
|
||||
contextStatus = await checkFileContextStatus(relPath, fullPath, metadata, cline.apiConversationHistory)
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
smartRead: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
@ -45,7 +45,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
smartRead: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true)
|
||||
})
|
||||
|
|
@ -58,7 +58,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
smartRead: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ export const EXPERIMENT_IDS = {
|
|||
IMAGE_GENERATION: "imageGeneration",
|
||||
RUN_SLASH_COMMAND: "runSlashCommand",
|
||||
MULTIPLE_NATIVE_TOOL_CALLS: "multipleNativeToolCalls",
|
||||
SMART_CONTEXT_TRACKING: "smartContextTracking",
|
||||
SMART_READ: "smartRead",
|
||||
} as const satisfies Record<string, ExperimentId>
|
||||
|
||||
type _AssertExperimentIds = AssertEqual<Equals<ExperimentId, Values<typeof EXPERIMENT_IDS>>>
|
||||
|
|
@ -25,7 +25,7 @@ export const experimentConfigsMap: Record<ExperimentKey, ExperimentConfig> = {
|
|||
IMAGE_GENERATION: { enabled: false },
|
||||
RUN_SLASH_COMMAND: { enabled: false },
|
||||
MULTIPLE_NATIVE_TOOL_CALLS: { enabled: false },
|
||||
SMART_CONTEXT_TRACKING: { enabled: false },
|
||||
SMART_READ: { enabled: false },
|
||||
}
|
||||
|
||||
export const experimentDefault = Object.fromEntries(
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ describe("mergeExtensionState", () => {
|
|||
runSlashCommand: false,
|
||||
nativeToolCalling: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
smartRead: false,
|
||||
} as Record<ExperimentId, boolean>,
|
||||
checkpointTimeout: DEFAULT_CHECKPOINT_TIMEOUT_SECONDS + 5,
|
||||
}
|
||||
|
|
@ -264,7 +264,7 @@ describe("mergeExtensionState", () => {
|
|||
runSlashCommand: false,
|
||||
nativeToolCalling: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
smartRead: false,
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -831,6 +831,10 @@
|
|||
"MULTIPLE_NATIVE_TOOL_CALLS": {
|
||||
"name": "Parallel tool calls",
|
||||
"description": "When enabled, the native protocol can execute multiple tools in a single assistant message turn."
|
||||
},
|
||||
"SMART_READ": {
|
||||
"name": "Smart file context tracking",
|
||||
"description": "When enabled, Roo will skip re-reading files that are already in the conversation context. This reduces token usage and speeds up responses when working with files you've recently viewed."
|
||||
}
|
||||
},
|
||||
"promptCaching": {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue