104 lines
2.5 KiB
Go
104 lines
2.5 KiB
Go
package session
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"hash/crc32"
|
|
"ollie/backend"
|
|
"ollie/paths"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
// --- Code Completion ---
|
|
|
|
// Complete performs a stateless one-shot code completion via backend.Generate.
|
|
func (s *Manager) Complete(cwd, filePath, prefix, suffix, extraContext string) (string, error) {
|
|
if cwd == "" {
|
|
cwd, _ = os.Getwd()
|
|
}
|
|
cwd = paths.ExpandHome(os.ExpandEnv(cwd))
|
|
|
|
model := os.Getenv("OLLIE_COMPLETE_MODEL")
|
|
backendName := os.Getenv("OLLIE_COMPLETE_BACKEND")
|
|
if model == "" || backendName == "" {
|
|
return "", fmt.Errorf("OLLIE_COMPLETE_MODEL and OLLIE_COMPLETE_BACKEND must be set")
|
|
}
|
|
|
|
const prefixMax = 12000
|
|
const suffixMax = 1000
|
|
if len(prefix) > prefixMax {
|
|
prefix = prefix[len(prefix)-prefixMax:]
|
|
}
|
|
if len(suffix) > suffixMax {
|
|
suffix = suffix[:suffixMax]
|
|
}
|
|
|
|
fileHint := ""
|
|
if filePath != "" {
|
|
fileHint = " in " + filePath
|
|
}
|
|
contextBlock := ""
|
|
if extraContext != "" {
|
|
contextBlock = "\n" + extraContext
|
|
}
|
|
prompt := fmt.Sprintf(`Implement the code at the cursor%s. The prefix ends at the point where new code is needed. Write the implementation — do not echo stubs, TODOs, or placeholder returns from the prefix. Output ONLY raw code. No reasoning, no shell commands, no explanations, no markdown fences, no backticks, no preamble. Your entire response must be valid code that can be inserted directly into the file.
|
|
%s
|
|
<prefix>
|
|
%s
|
|
</prefix>
|
|
<suffix>
|
|
%s
|
|
</suffix>`, fileHint, contextBlock, prefix, suffix)
|
|
|
|
result, err := backend.Generate(context.Background(), backend.GenerateRequest{
|
|
Prompt: prompt,
|
|
Backend: backendName,
|
|
Model: model,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
result = stripCompletionNoise(result)
|
|
result = stripPrefixEcho(prefix, result)
|
|
return result, nil
|
|
}
|
|
|
|
func stripCompletionNoise(s string) string {
|
|
var lines []string
|
|
for _, line := range strings.Split(s, "\n") {
|
|
trimmed := strings.TrimSpace(line)
|
|
if strings.HasPrefix(trimmed, "```") {
|
|
continue
|
|
}
|
|
if trimmed == "<prefix>" || trimmed == "</prefix>" ||
|
|
trimmed == "<suffix>" || trimmed == "</suffix>" {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(trimmed, ":: ") {
|
|
continue
|
|
}
|
|
lines = append(lines, line)
|
|
}
|
|
return strings.Join(lines, "\n")
|
|
}
|
|
|
|
func stripPrefixEcho(prefix, result string) string {
|
|
tailMax := 200
|
|
if len(prefix) < tailMax {
|
|
tailMax = len(prefix)
|
|
}
|
|
for i := tailMax; i > 0; i-- {
|
|
tail := prefix[len(prefix)-i:]
|
|
if strings.HasPrefix(result, tail) {
|
|
return result[len(tail):]
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func crc32Str(s string) uint32 {
|
|
return crc32.ChecksumIEEE([]byte(s))
|
|
}
|