LLM-18251: change per provider listening to only cloud completion provider listening for dynamic debouncing

(cherry picked from commit 4218fcee6e17ab03e9aea136bc257c37a539a1df)


(cherry picked from commit 91bb294944c12b1215e8ff4d2db610e1e5585c02)

IJ-MR-175246

GitOrigin-RevId: 0b07fce6d913f5d3c0c2b3d9de83f33af0709523
This commit is contained in:
Roman Chertishchev
2025-09-10 19:52:32 +02:00
committed by intellij-monorepo-bot
parent c7104b975b
commit 5ba949ceaa
3 changed files with 0 additions and 102 deletions

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.inline.completion
import com.intellij.codeInsight.inline.completion.debounce.InlineCompletionAdaptiveDebounceListener
import com.intellij.codeInsight.inline.completion.editor.InlineCompletionEditorType
import com.intellij.codeInsight.inline.completion.elements.InlineCompletionElement
import com.intellij.codeInsight.inline.completion.listeners.InlineSessionWiseCaretListener
@@ -85,9 +84,6 @@ abstract class InlineCompletionHandler @ApiStatus.Internal constructor(
invalidationListeners.addListener(logsListener)
addEventListener(UserFactorsListener())
// Adaptive debounce listener: tracks acceptance/rejection outcomes for the last 10 minutes
addEventListener(InlineCompletionAdaptiveDebounceListener(editor))
Disposer.register(parentDisposable, /* child = */ executor)
}

View File

@@ -1,39 +0,0 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.inline.completion.debounce
import com.intellij.codeInsight.inline.completion.InlineCompletionEventAdapter
import com.intellij.codeInsight.inline.completion.InlineCompletionEventType
import com.intellij.codeInsight.inline.completion.logs.InlineCompletionUsageTracker.ShownEvents.FinishType
import com.intellij.codeInsight.inline.completion.session.InlineCompletionSession
import com.intellij.openapi.editor.Editor
/**
* Listener that observes inline completion lifecycle and records
* accept/reject finish type into [InlineCompletionFinishedCompletionsStorage] per provider.
*/
internal class InlineCompletionAdaptiveDebounceListener(private val editor: Editor) : InlineCompletionEventAdapter {
private fun serviceOrNull(): InlineCompletionFinishedCompletionsStorage? = editor.project?.let { InlineCompletionFinishedCompletionsStorage.getInstance(it) }
override fun onHide(event: InlineCompletionEventType.Hide) {
val result = when (event.finishType) {
FinishType.CARET_CHANGED,
FinishType.EDITOR_REMOVED,
FinishType.FOCUS_LOST,
FinishType.TYPED,
FinishType.EMPTY,
FinishType.ERROR,
FinishType.OTHER,
FinishType.BACKSPACE_PRESSED,
FinishType.KEY_PRESSED,
FinishType.INVALIDATED,
FinishType.MOUSE_PRESSED,
FinishType.DOCUMENT_CHANGED,
-> InlineCompletionFinishedCompletionsStorage.Result.OTHER
FinishType.ESCAPE_PRESSED -> InlineCompletionFinishedCompletionsStorage.Result.REJECTED
FinishType.SELECTED -> InlineCompletionFinishedCompletionsStorage.Result.ACCEPTED
}
val provider = InlineCompletionSession.getOrNull(editor)?.provider?.id
provider?.let { serviceOrNull()?.record(it, result) }
}
}

View File

@@ -1,59 +0,0 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.inline.completion.debounce
import com.intellij.codeInsight.inline.completion.InlineCompletionProviderID
import com.intellij.codeInsight.inline.completion.debounce.InlineCompletionFinishedCompletionsStorage.Companion.EXPIRATION_MS
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project
import org.jetbrains.annotations.ApiStatus
import java.util.*
/**
* Project-level container of recent inline-completions for adaptive debounce tuning.
*
* Retains completions for the last [EXPIRATION_MS] milliseconds (10 minutes) and discards older ones.
*/
@Service(Service.Level.PROJECT)
@ApiStatus.Internal
class InlineCompletionFinishedCompletionsStorage {
enum class Result { ACCEPTED, REJECTED, OTHER }
data class FinishedCompletion(val providerId: InlineCompletionProviderID, val result: Result, val finishTime: Long)
private val completionsPerProvider: MutableMap<InlineCompletionProviderID, ArrayDeque<FinishedCompletion>> = HashMap()
fun record(provider: InlineCompletionProviderID, result: Result) {
val now = System.currentTimeMillis()
cleanupExpired(now)
val q = completionsPerProvider.getOrPut(provider) { ArrayDeque() }
q.addLast(FinishedCompletion(provider, result, now))
}
/**
* Returns a snapshot of recent completions with timestamps (most recent at the end) for the given provider.
*/
fun getRecentCompletions(provider: InlineCompletionProviderID): List<FinishedCompletion> {
cleanupExpired(System.currentTimeMillis())
return completionsPerProvider[provider]?.toList().orEmpty()
}
private fun cleanupExpired(now: Long) {
val threshold = now - EXPIRATION_MS
val it = completionsPerProvider.entries.iterator()
while (it.hasNext()) {
val entry = it.next()
val q = entry.value
while (true) {
val first = q.peekFirst() ?: break
if (first.finishTime < threshold) q.removeFirst() else break
}
if (q.isEmpty()) it.remove()
}
}
companion object {
private const val EXPIRATION_MS: Long = 10 * 60 * 1000 // 10 minutes
fun getInstance(project: Project): InlineCompletionFinishedCompletionsStorage = project.service()
}
}