133 lines
3.1 KiB
Go
133 lines
3.1 KiB
Go
package winlimit
|
|
|
|
import (
|
|
"cursor-api-proxy/internal/env"
|
|
"runtime"
|
|
)
|
|
|
|
const WinPromptOmissionPrefix = "[Earlier messages omitted: Windows command-line length limit.]\n\n"
|
|
|
|
type FitPromptResult struct {
|
|
OK bool
|
|
Args []string
|
|
Truncated bool
|
|
OriginalLength int
|
|
FinalPromptLength int
|
|
Error string
|
|
}
|
|
|
|
func estimateCmdlineLength(resolved env.AgentCommand) int {
|
|
argv := append([]string{resolved.Command}, resolved.Args...)
|
|
if resolved.WindowsVerbatimArguments {
|
|
n := 0
|
|
for _, a := range argv {
|
|
n += len(a)
|
|
}
|
|
if len(argv) > 1 {
|
|
n += len(argv) - 1
|
|
}
|
|
return n + 512
|
|
}
|
|
dstLen := 0
|
|
for _, a := range argv {
|
|
dstLen += len(a)
|
|
}
|
|
dstLen = dstLen*2 + len(argv)*2
|
|
if len(argv) > 1 {
|
|
dstLen += len(argv) - 1
|
|
}
|
|
return dstLen + 512
|
|
}
|
|
|
|
func FitPromptToWinCmdline(agentBin string, fixedArgs []string, prompt string, maxCmdline int, cwd string) FitPromptResult {
|
|
if runtime.GOOS != "windows" {
|
|
args := make([]string, len(fixedArgs)+1)
|
|
copy(args, fixedArgs)
|
|
args[len(fixedArgs)] = prompt
|
|
return FitPromptResult{
|
|
OK: true,
|
|
Args: args,
|
|
Truncated: false,
|
|
OriginalLength: len(prompt),
|
|
FinalPromptLength: len(prompt),
|
|
}
|
|
}
|
|
|
|
e := env.OsEnvToMap()
|
|
measured := func(p string) int {
|
|
args := make([]string, len(fixedArgs)+1)
|
|
copy(args, fixedArgs)
|
|
args[len(fixedArgs)] = p
|
|
resolved := env.ResolveAgentCommand(agentBin, args, e, cwd)
|
|
return estimateCmdlineLength(resolved)
|
|
}
|
|
|
|
if measured("") > maxCmdline {
|
|
return FitPromptResult{
|
|
OK: false,
|
|
Error: "Windows command line exceeds the configured limit even without a prompt; shorten workspace path, model id, or CURSOR_BRIDGE_WIN_CMDLINE_MAX.",
|
|
}
|
|
}
|
|
|
|
if measured(prompt) <= maxCmdline {
|
|
args := make([]string, len(fixedArgs)+1)
|
|
copy(args, fixedArgs)
|
|
args[len(fixedArgs)] = prompt
|
|
return FitPromptResult{
|
|
OK: true,
|
|
Args: args,
|
|
Truncated: false,
|
|
OriginalLength: len(prompt),
|
|
FinalPromptLength: len(prompt),
|
|
}
|
|
}
|
|
|
|
prefix := WinPromptOmissionPrefix
|
|
if measured(prefix) > maxCmdline {
|
|
return FitPromptResult{
|
|
OK: false,
|
|
Error: "Windows command line too long to fit even the truncation notice; shorten workspace path or flags.",
|
|
}
|
|
}
|
|
|
|
lo, hi, best := 0, len(prompt), 0
|
|
for lo <= hi {
|
|
mid := (lo + hi) / 2
|
|
var tail string
|
|
if mid > 0 {
|
|
tail = prompt[len(prompt)-mid:]
|
|
}
|
|
candidate := prefix + tail
|
|
if measured(candidate) <= maxCmdline {
|
|
best = mid
|
|
lo = mid + 1
|
|
} else {
|
|
hi = mid - 1
|
|
}
|
|
}
|
|
|
|
var finalPrompt string
|
|
if best == 0 {
|
|
finalPrompt = prefix
|
|
} else {
|
|
finalPrompt = prefix + prompt[len(prompt)-best:]
|
|
}
|
|
|
|
args := make([]string, len(fixedArgs)+1)
|
|
copy(args, fixedArgs)
|
|
args[len(fixedArgs)] = finalPrompt
|
|
return FitPromptResult{
|
|
OK: true,
|
|
Args: args,
|
|
Truncated: true,
|
|
OriginalLength: len(prompt),
|
|
FinalPromptLength: len(finalPrompt),
|
|
}
|
|
}
|
|
|
|
func WarnPromptTruncated(originalLength, finalLength int) {
|
|
_ = originalLength
|
|
_ = finalLength
|
|
// fmt.Fprintf skipped to avoid import; caller may log as needed
|
|
}
|