Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
85 changes: 20 additions & 65 deletions src/core/task/Task.ts
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
private readonly _isHistoryTask: boolean
// No streaming parser is required.
assistantMessageParser?: undefined
private providerProfileChangeListener?: (config: { name: string; provider?: string }) => void

// Native tool call streaming state (track which index each tool is at)
private streamingToolCallIndices: Map<string, number> = new Map()
Expand Down Expand Up @@ -562,9 +561,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {

this.messageQueueService.on("stateChanged", this.messageQueueStateChangedHandler)

// Listen for provider profile changes to update parser state
this.setupProviderProfileChangeListener(provider)

// Set up diff strategy
this.diffStrategy = new MultiSearchReplaceDiffStrategy(diffFuzzyThreshold)

Expand Down Expand Up @@ -690,35 +686,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
}
}

/**
* Sets up a listener for provider profile changes.
*
* @private
* @param provider - The ClineProvider instance to listen to
*/
private setupProviderProfileChangeListener(provider: ClineProvider): void {
// Only set up listener if provider has the on method (may not exist in test mocks)
if (typeof provider.on !== "function") {
return
}

this.providerProfileChangeListener = async () => {
try {
const newState = await provider.getState()
if (newState?.apiConfiguration) {
this.updateApiConfiguration(newState.apiConfiguration)
}
} catch (error) {
console.error(
`[Task#${this.taskId}.${this.instanceId}] Failed to update API configuration on profile change:`,
error,
)
}
}

provider.on(RooCodeEventName.ProviderProfileChanged, this.providerProfileChangeListener)
}

/**
* Wait for the task mode to be initialized before proceeding.
* This method ensures that any operations depending on the task mode
Expand Down Expand Up @@ -1537,6 +1504,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
if (provider) {
if (mode) {
await provider.setMode(mode)
this._taskMode = mode
}

if (providerProfile) {
Expand All @@ -1545,6 +1513,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// Update this task's API configuration to match the new profile
// This ensures the parser state is synchronized with the selected model
const newState = await provider.getState()
this.setTaskApiConfigName(newState?.currentApiConfigName ?? providerProfile)
if (newState?.apiConfiguration) {
this.updateApiConfiguration(newState.apiConfiguration)
}
Expand Down Expand Up @@ -1591,7 +1560,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
// Get condensing configuration
const state = await this.providerRef.deref()?.getState()
const customCondensingPrompt = state?.customSupportPrompts?.CONDENSE
const { mode, apiConfiguration } = state ?? {}
// Use task-local values, not provider state, to prevent cross-task configuration leaks.
const mode = await this.getTaskMode()
const apiConfiguration = this.apiConfiguration

const { contextTokens: prevContextTokens } = this.getTokenUsage()

Expand Down Expand Up @@ -2277,19 +2248,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
console.error("Error cancelling current request:", error)
}

// Remove provider profile change listener
try {
if (this.providerProfileChangeListener) {
const provider = this.providerRef.deref()
if (provider) {
provider.off(RooCodeEventName.ProviderProfileChanged, this.providerProfileChangeListener)
}
this.providerProfileChangeListener = undefined
}
} catch (error) {
console.error("Error removing provider profile change listener:", error)
}

// Dispose message queue and remove event listeners.
try {
if (this.messageQueueStateChangedHandler) {
Expand Down Expand Up @@ -2581,7 +2539,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
const showRooIgnoredFiles = state?.showRooIgnoredFiles ?? false
const includeDiagnosticMessages = state?.includeDiagnosticMessages ?? true
const maxDiagnosticMessages = state?.maxDiagnosticMessages ?? 50
const currentMode = state?.mode ?? defaultModeSlug
const currentMode = await this.getTaskMode()

const { content: parsedUserContent, mode: slashCommandMode } = await processUserContentMentions({
userContent: currentUserContent,
Expand Down Expand Up @@ -3782,16 +3740,11 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {

const state = await this.providerRef.deref()?.getState()

const {
mode,
customModes,
customModePrompts,
customInstructions,
experiments,
language,
apiConfiguration,
enableSubfolderRules,
} = state ?? {}
const { customModes, customModePrompts, customInstructions, experiments, language, enableSubfolderRules } =
state ?? {}
// Use task-local values, not provider state, to prevent cross-task configuration leaks.
const mode = await this.getTaskMode()
const apiConfiguration = this.apiConfiguration

return await (async () => {
const provider = this.providerRef.deref()
Expand Down Expand Up @@ -3857,7 +3810,10 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {

private async handleContextWindowExceededError(): Promise<void> {
const state = await this.providerRef.deref()?.getState()
const { profileThresholds = {}, mode, apiConfiguration } = state ?? {}
const { profileThresholds = {} } = state ?? {}
// Use task-local values, not provider state, to prevent cross-task configuration leaks.
const mode = await this.getTaskMode()
const apiConfiguration = this.apiConfiguration

const { contextTokens } = this.getTokenUsage()
await this.safeEnsureModelFetched()
Expand Down Expand Up @@ -3997,9 +3953,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
* the `api_req_rate_limit_wait` say type (not an error).
*/
private async maybeWaitForProviderRateLimit(retryAttempt: number): Promise<void> {
const state = await this.providerRef.deref()?.getState()
const rateLimitSeconds =
state?.apiConfiguration?.rateLimitSeconds ?? this.apiConfiguration?.rateLimitSeconds ?? 0
const rateLimitSeconds = this.apiConfiguration?.rateLimitSeconds ?? 0
Comment thread
coderabbitai[bot] marked this conversation as resolved.

const lastRequestTime = this.rateLimitClock.getLastRequestTime()
if (rateLimitSeconds <= 0 || !lastRequestTime) {
Expand Down Expand Up @@ -4032,14 +3986,15 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
const state = await this.providerRef.deref()?.getState()

const {
apiConfiguration,
autoApprovalEnabled,
requestDelaySeconds,
mode,
autoCondenseContext = true,
autoCondenseContextPercent = 100,
profileThresholds = {},
} = state ?? {}
// Use task-local values, not provider state, to prevent cross-task configuration leaks.
const mode = await this.getTaskMode()
const apiConfiguration = this.apiConfiguration
Comment thread
coderabbitai[bot] marked this conversation as resolved.

// Get condensing configuration for automatic triggers.
const customCondensingPrompt = state?.customSupportPrompts?.CONDENSE
Expand Down Expand Up @@ -4452,7 +4407,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {

// Respect provider rate limit window
let rateLimitDelay = 0
const rateLimit = (state?.apiConfiguration ?? this.apiConfiguration)?.rateLimitSeconds || 0
const rateLimit = this.apiConfiguration?.rateLimitSeconds ?? 0
const lastRequestTime = this.rateLimitClock.getLastRequestTime()
if (lastRequestTime && rateLimit > 0) {
const elapsed = performance.now() - lastRequestTime
Expand Down
Loading
Loading