From 359e0400a97c7d00eed8359a028b454b098c5069 Mon Sep 17 00:00:00 2001 From: Naman Kumar Date: Wed, 15 Jan 2025 13:09:11 +0530 Subject: [PATCH] Make sure precomputed intent is not stale (#6572) closes: https://linear.app/sourcegraph/issue/CODY-4613/non-deterministic-intent-detection We precompute the intent while the user is typing the input with a 300ms debounce. It is possible that after the last intent detection the user may change the query and submit within 300ms, causing the detected intent to be stale and often different than the intent for the final query. This PR fixes that behavior by checking if the query has changed since the last intent detection and ignoring the pre-computed intent in case the query was changed afterwards. ## Test plan https://sourcegraph.slack.com/archives/C07EQBRSF35/p1735859984632339 ## Changelog --- vscode/webviews/chat/Transcript.tsx | 55 +++++++++++++++++------------ 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/vscode/webviews/chat/Transcript.tsx b/vscode/webviews/chat/Transcript.tsx index 1fff91edf4c3..2b15845abd0f 100644 --- a/vscode/webviews/chat/Transcript.tsx +++ b/vscode/webviews/chat/Transcript.tsx @@ -247,6 +247,12 @@ interface TranscriptInteractionProps }) => void } +interface IntentResults { + query: string + intent: ChatMessage['intent'] + allScores?: { intent: string; score: number }[] +} + const TranscriptInteraction: FC = memo(props => { const { interaction: { humanMessage, assistantMessage }, @@ -266,14 +272,7 @@ const TranscriptInteraction: FC = memo(props => { smartApplyEnabled, editorRef: parentEditorRef, } = props - const [intentResults, setIntentResults] = useMutatedValue< - | { - intent: ChatMessage['intent'] - allScores?: { intent: string; score: number }[] - } - | undefined - | null - >() + const [intentResults, setIntentResults] = useMutatedValue() const { activeChatContext, setActiveChatContext } = props const humanEditorRef = useRef(null) @@ -309,10 +308,14 @@ const TranscriptInteraction: FC = memo(props => { return } + const { intent, intentScores } = intentFromSubmit + ? { intent: intentFromSubmit, intentScores: undefined } + : getIntentProps(editorValue, intentResults.current) + const commonProps = { editorValue, - intent: intentFromSubmit || intentResults.current?.intent, - intentScores: intentFromSubmit ? undefined : intentResults.current?.allScores, + intent, + intentScores, manuallySelectedIntent: !!intentFromSubmit, traceparent, } @@ -371,18 +374,16 @@ const TranscriptInteraction: FC = memo(props => { setIntentResults(undefined) - const subscription = extensionAPI - .detectIntent( - inputTextWithMappedContextChipsFromPromptEditorState(editorValue.editorState) - ) - .subscribe({ - next: value => { - setIntentResults(value) - }, - error: error => { - console.error('Error detecting intent:', error) - }, - }) + const query = inputTextWithMappedContextChipsFromPromptEditorState(editorValue.editorState) + + const subscription = extensionAPI.detectIntent(query).subscribe({ + next: value => { + setIntentResults(value && { ...value, query }) + }, + error: error => { + console.error('Error detecting intent:', error) + }, + }) // Clean up subscription if component unmounts return () => subscription.unsubscribe() @@ -775,3 +776,13 @@ function reevaluateSearchWithSelectedFilters({ selectedFilters, }) } + +const getIntentProps = (editorValue: SerializedPromptEditorValue, results?: IntentResults | null) => { + const query = inputTextWithMappedContextChipsFromPromptEditorState(editorValue.editorState) + + if (query === results?.query) { + return { intent: results.intent, intentScores: results.allScores } + } + + return {} +}