mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
feat: gate smart context tracking behind experimental setting
Added new 'smartContextTracking' experiment to gate the file context tracking optimization. When disabled (default), the read_file tools behave as before. When enabled, files that haven't changed and still have content in the conversation context return a short 'unchanged' response instead of re-reading the full content. Changes: - Added smartContextTracking to experimentIds in packages/types - Added SMART_CONTEXT_TRACKING to experiments.ts - Updated simpleReadFileTool.ts to check experiment before optimization - Updated ReadFileTool.ts to check experiment before optimization
This commit is contained in:
parent
7b82c91090
commit
9f29251b8a
5 changed files with 52 additions and 10 deletions
|
|
@ -13,6 +13,7 @@ export const experimentIds = [
|
|||
"imageGeneration",
|
||||
"runSlashCommand",
|
||||
"multipleNativeToolCalls",
|
||||
"smartContextTracking",
|
||||
] as const
|
||||
|
||||
export const experimentIdsSchema = z.enum(experimentIds)
|
||||
|
|
@ -30,6 +31,7 @@ export const experimentsSchema = z.object({
|
|||
imageGeneration: z.boolean().optional(),
|
||||
runSlashCommand: z.boolean().optional(),
|
||||
multipleNativeToolCalls: z.boolean().optional(),
|
||||
smartContextTracking: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export type Experiments = z.infer<typeof experimentsSchema>
|
||||
|
|
|
|||
|
|
@ -9,7 +9,12 @@ import { formatResponse } from "../prompts/responses"
|
|||
import { getModelMaxOutputTokens } from "../../shared/api"
|
||||
import { t } from "../../i18n"
|
||||
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
||||
import { checkFileContextStatus, getReReadNotice } from "../context-tracking/FileContextStatusChecker"
|
||||
import {
|
||||
checkFileContextStatus,
|
||||
getReReadNotice,
|
||||
FileContextStatus,
|
||||
} from "../context-tracking/FileContextStatusChecker"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { countFileLines } from "../../integrations/misc/line-counter"
|
||||
|
|
@ -142,6 +147,13 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
try {
|
||||
const filesToApprove: FileResult[] = []
|
||||
|
||||
// Check if smart context tracking experiment is enabled
|
||||
const experimentState = await task.providerRef.deref()?.getState()
|
||||
const isSmartContextTrackingEnabled = experiments.isEnabled(
|
||||
experimentState?.experiments ?? {},
|
||||
EXPERIMENT_IDS.SMART_CONTEXT_TRACKING,
|
||||
)
|
||||
|
||||
for (const fileResult of fileResults) {
|
||||
const relPath = fileResult.path
|
||||
const fullPath = path.resolve(task.cwd, relPath)
|
||||
|
|
@ -191,9 +203,12 @@ export class ReadFileTool extends BaseTool<"read_file"> {
|
|||
continue
|
||||
}
|
||||
|
||||
// Check if file needs to be re-read based on context status
|
||||
// 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 (!fileResult.lineRanges || fileResult.lineRanges.length === 0) {
|
||||
if (
|
||||
isSmartContextTrackingEnabled &&
|
||||
(!fileResult.lineRanges || fileResult.lineRanges.length === 0)
|
||||
) {
|
||||
const metadata = await task.fileContextTracker.getTaskMetadata(task.taskId)
|
||||
const contextStatus = await checkFileContextStatus(
|
||||
relPath,
|
||||
|
|
|
|||
|
|
@ -7,7 +7,12 @@ import { formatResponse } from "../prompts/responses"
|
|||
import { t } from "../../i18n"
|
||||
import { ToolUse, AskApproval, HandleError, PushToolResult, RemoveClosingTag } from "../../shared/tools"
|
||||
import { RecordSource } from "../context-tracking/FileContextTrackerTypes"
|
||||
import { checkFileContextStatus, getReReadNotice } from "../context-tracking/FileContextStatusChecker"
|
||||
import {
|
||||
checkFileContextStatus,
|
||||
getReReadNotice,
|
||||
FileContextStatus,
|
||||
} from "../context-tracking/FileContextStatusChecker"
|
||||
import { EXPERIMENT_IDS, experiments } from "../../shared/experiments"
|
||||
import { isPathOutsideWorkspace } from "../../utils/pathUtils"
|
||||
import { getReadablePath } from "../../utils/path"
|
||||
import { countFileLines } from "../../integrations/misc/line-counter"
|
||||
|
|
@ -86,15 +91,30 @@ export async function simpleReadFileTool(
|
|||
return
|
||||
}
|
||||
|
||||
// Check if file needs to be re-read based on context status
|
||||
const metadata = await cline.fileContextTracker.getTaskMetadata(cline.taskId)
|
||||
const contextStatus = await checkFileContextStatus(relPath, fullPath, metadata, cline.apiConversationHistory)
|
||||
// Check if smart context tracking experiment is enabled
|
||||
const state = await cline.providerRef.deref()?.getState()
|
||||
const isSmartContextTrackingEnabled = experiments.isEnabled(
|
||||
state?.experiments ?? {},
|
||||
EXPERIMENT_IDS.SMART_CONTEXT_TRACKING,
|
||||
)
|
||||
|
||||
// If we need to re-read, get the notice explaining why (for later use)
|
||||
const reReadNotice = getReReadNotice(contextStatus.reason)
|
||||
// Check if file needs to be re-read based on context status (only if experiment enabled)
|
||||
let contextStatus: FileContextStatus = {
|
||||
shouldReRead: true,
|
||||
reason: "never_read",
|
||||
}
|
||||
let reReadNotice: string | undefined = undefined
|
||||
|
||||
if (isSmartContextTrackingEnabled) {
|
||||
const metadata = await cline.fileContextTracker.getTaskMetadata(cline.taskId)
|
||||
contextStatus = await checkFileContextStatus(relPath, fullPath, metadata, cline.apiConversationHistory)
|
||||
|
||||
// If we need to re-read, get the notice explaining why (for later use)
|
||||
reReadNotice = getReReadNotice(contextStatus.reason)
|
||||
}
|
||||
|
||||
// Get max read file line setting
|
||||
const { maxReadFileLine = -1 } = (await cline.providerRef.deref()?.getState()) ?? {}
|
||||
const { maxReadFileLine = -1 } = state ?? {}
|
||||
|
||||
// Create approval message
|
||||
const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
@ -44,6 +45,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(true)
|
||||
})
|
||||
|
|
@ -56,6 +58,7 @@ describe("experiments", () => {
|
|||
imageGeneration: false,
|
||||
runSlashCommand: false,
|
||||
multipleNativeToolCalls: false,
|
||||
smartContextTracking: false,
|
||||
}
|
||||
expect(Experiments.isEnabled(experiments, EXPERIMENT_IDS.POWER_STEERING)).toBe(false)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ export const EXPERIMENT_IDS = {
|
|||
IMAGE_GENERATION: "imageGeneration",
|
||||
RUN_SLASH_COMMAND: "runSlashCommand",
|
||||
MULTIPLE_NATIVE_TOOL_CALLS: "multipleNativeToolCalls",
|
||||
SMART_CONTEXT_TRACKING: "smartContextTracking",
|
||||
} as const satisfies Record<string, ExperimentId>
|
||||
|
||||
type _AssertExperimentIds = AssertEqual<Equals<ExperimentId, Values<typeof EXPERIMENT_IDS>>>
|
||||
|
|
@ -24,6 +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 },
|
||||
}
|
||||
|
||||
export const experimentDefault = Object.fromEntries(
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue