mirror of
https://gitflic.ru/project/openide/openide.git
synced 2025-12-16 14:23:28 +07:00
LLM-18251: introduce adaptive debounce for cloud completion
(cherry picked from commit 730bbb63918e8fd8b82ef2cb8720f6a8a2007006) (cherry picked from commit d71601c2661630be1024b5f9b9451e7dc678d34b) IJ-MR-175246 GitOrigin-RevId: 95dc7c63e9de04256335f48cfb8a26f87cec5c0d
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9966f71675
commit
dde4de27ea
@@ -1,6 +1,7 @@
|
||||
// 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
|
||||
@@ -84,6 +85,9 @@ 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)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// 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.openapi.editor.Editor
|
||||
|
||||
/**
|
||||
* Listener that observes inline completion lifecycle and records
|
||||
* accept/reject finish type into [InlineCompletionFinishedCompletionsStorage].
|
||||
*/
|
||||
internal class InlineCompletionAdaptiveDebounceListener(private val editor: Editor) : InlineCompletionEventAdapter {
|
||||
|
||||
private fun serviceOrNull(): InlineCompletionFinishedCompletionsStorage? = editor.project?.let { InlineCompletionFinishedCompletionsStorage.getInstance(it) }
|
||||
|
||||
override fun onAfterInsert(event: InlineCompletionEventType.AfterInsert) {
|
||||
serviceOrNull()?.record(InlineCompletionFinishedCompletionsStorage.Result.ACCEPTED)
|
||||
}
|
||||
|
||||
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.SELECTED,
|
||||
FinishType.MOUSE_PRESSED,
|
||||
FinishType.DOCUMENT_CHANGED,
|
||||
-> InlineCompletionFinishedCompletionsStorage.Result.OTHER
|
||||
FinishType.ESCAPE_PRESSED -> InlineCompletionFinishedCompletionsStorage.Result.REJECTED
|
||||
}
|
||||
serviceOrNull()?.record(result)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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.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 result: Result, val finishTime: Long)
|
||||
|
||||
private val previousCompletions = ArrayDeque<FinishedCompletion>()
|
||||
|
||||
@Synchronized
|
||||
fun record(result: Result) {
|
||||
val now = System.currentTimeMillis()
|
||||
cleanupExpired(now)
|
||||
previousCompletions.addLast(FinishedCompletion(result, now))
|
||||
}
|
||||
|
||||
/** Returns a snapshot of recent actions with timestamps (most recent at the end). */
|
||||
@Synchronized
|
||||
fun getRecentCompletions(): List<FinishedCompletion> {
|
||||
cleanupExpired(System.currentTimeMillis())
|
||||
return ArrayList(previousCompletions)
|
||||
}
|
||||
|
||||
private fun cleanupExpired(now: Long) {
|
||||
val threshold = now - EXPIRATION_MS
|
||||
while (true) {
|
||||
val first = previousCompletions.peekFirst() ?: break
|
||||
if (first.finishTime < threshold) previousCompletions.removeFirst() else break
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val EXPIRATION_MS: Long = 10 * 60 * 1000 // 10 minutes
|
||||
fun getInstance(project: Project): InlineCompletionFinishedCompletionsStorage = project.service()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user