mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
perf(cli): skip impossible typo distance comparisons (#18977)
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import * as distance from '../shared/edit-distance'
|
||||
import { suggestCommands, unknownFlagData } from './command-suggestion'
|
||||
import type { CommandSpec } from './command-spec'
|
||||
|
||||
const specs: CommandSpec[] = [
|
||||
{ path: ['list'], summary: '', usage: '', allowedFlags: [] },
|
||||
{ path: ['remove'], summary: '', usage: '', allowedFlags: [], destructive: true }
|
||||
]
|
||||
|
||||
afterEach(() => vi.restoreAllMocks())
|
||||
|
||||
describe('suggestion distance work', () => {
|
||||
it('does no distance calculations for a long command, including destructive intent', () => {
|
||||
const spy = vi.spyOn(distance, 'levenshtein')
|
||||
expect(suggestCommands(specs, ['x'.repeat(32_768)])).toEqual([])
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('does no distance calculations for a long flag but still lists valid flags', () => {
|
||||
const spy = vi.spyOn(distance, 'levenshtein')
|
||||
expect(unknownFlagData('x'.repeat(32_768), ['worktree', 'json'])).toEqual({
|
||||
validFlags: ['json', 'worktree'],
|
||||
suggestions: [],
|
||||
nextSteps: ['Valid flags: --json, --worktree']
|
||||
})
|
||||
expect(spy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('keeps the inclusive three-edit suggestion boundary', () => {
|
||||
expect(suggestCommands(specs, ['listxxx'])).toEqual(['list'])
|
||||
expect(unknownFlagData('jsonxxx', ['json']).suggestions).toEqual(['json'])
|
||||
})
|
||||
|
||||
it('keeps the inclusive one-edit destructive intent boundary', () => {
|
||||
expect(suggestCommands(specs, ['remov'])).toEqual(['remove'])
|
||||
expect(suggestCommands(specs, ['remo'])).toEqual([])
|
||||
})
|
||||
|
||||
it('retains UTF-16 distance semantics at the length boundary', () => {
|
||||
expect(unknownFlagData('json😀x', ['json']).suggestions).toEqual(['json'])
|
||||
expect(unknownFlagData('json😀😀', ['json']).suggestions).toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -37,7 +37,10 @@ function destructiveVerbs(specs: CommandSpec[]): Set<string> {
|
||||
// input token is itself a near-miss of a destructive verb. #6303
|
||||
function intendsDestruction(inputToken: string, verbs: Set<string>): boolean {
|
||||
for (const verb of verbs) {
|
||||
if (levenshtein(inputToken, verb) <= DESTRUCTIVE_INTENT_THRESHOLD) {
|
||||
if (
|
||||
Math.abs(inputToken.length - verb.length) <= DESTRUCTIVE_INTENT_THRESHOLD &&
|
||||
levenshtein(inputToken, verb) <= DESTRUCTIVE_INTENT_THRESHOLD
|
||||
) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -85,7 +88,9 @@ export function suggestCommands(specs: CommandSpec[], commandPath: string[]): st
|
||||
continue
|
||||
}
|
||||
seen.add(joined)
|
||||
scored.push({ label: joined, distance: levenshtein(input, joined) })
|
||||
if (Math.abs(input.length - joined.length) <= SUGGESTION_THRESHOLD) {
|
||||
scored.push({ label: joined, distance: levenshtein(input, joined) })
|
||||
}
|
||||
}
|
||||
}
|
||||
return rankByDistance(scored)
|
||||
@@ -106,9 +111,13 @@ export type FlagErrorData = {
|
||||
}
|
||||
|
||||
function suggestFlags(flag: string, validFlags: string[]): string[] {
|
||||
return rankByDistance(
|
||||
validFlags.map((candidate) => ({ label: candidate, distance: levenshtein(flag, candidate) }))
|
||||
)
|
||||
const scored: { label: string; distance: number }[] = []
|
||||
for (const candidate of validFlags) {
|
||||
if (Math.abs(flag.length - candidate.length) <= SUGGESTION_THRESHOLD) {
|
||||
scored.push({ label: candidate, distance: levenshtein(flag, candidate) })
|
||||
}
|
||||
}
|
||||
return rankByDistance(scored)
|
||||
}
|
||||
|
||||
// Why: include the accepted set so agents can recover without another help call.
|
||||
|
||||
Reference in New Issue
Block a user