61 lines
1.7 KiB
Go
61 lines
1.7 KiB
Go
package server
|
|
|
|
import (
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
|
|
"github.com/daniel/cursor-adapter/internal/types"
|
|
)
|
|
|
|
// Cowork-style mount path: /sessions/<adjective>-<adjective>-<color>/mnt/<folder>
|
|
// (and any deeper subpath; we capture only the mount root).
|
|
var mountPathRe = regexp.MustCompile(`/sessions/[a-z][a-z0-9]*(?:-[a-z][a-z0-9]*)+/mnt/[^\s/'"]+`)
|
|
|
|
// extractMountHints walks all prior tool_result blocks in the conversation
|
|
// and returns any Cowork-style /sessions/<id>/mnt/<folder> mount roots
|
|
// they reveal, deduped & sorted.
|
|
//
|
|
// This is purely stateless — we re-derive the set from the request body
|
|
// every turn. No server-side cache to invalidate, and it survives proxy
|
|
// restarts because the caller (Claude Desktop) replays the full history
|
|
// on each request anyway.
|
|
func extractMountHints(req types.AnthropicMessagesRequest) []string {
|
|
seen := map[string]struct{}{}
|
|
for _, m := range req.Messages {
|
|
for _, b := range m.Content {
|
|
if b.Type != "tool_result" {
|
|
continue
|
|
}
|
|
for _, p := range mountPathRe.FindAllString(renderToolResultContent(b.Content), -1) {
|
|
seen[p] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
if len(seen) == 0 {
|
|
return nil
|
|
}
|
|
out := make([]string, 0, len(seen))
|
|
for p := range seen {
|
|
out = append(out, p)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// renderMountHints turns a list of mount roots into a prompt section the
|
|
// brain can refer to. Returns "" when there are no hints.
|
|
func renderMountHints(hints []string) string {
|
|
if len(hints) == 0 {
|
|
return ""
|
|
}
|
|
var b strings.Builder
|
|
b.WriteString("Known host-mount paths (discovered earlier in this conversation, prefer these for any host file work):\n")
|
|
for _, h := range hints {
|
|
b.WriteString("- ")
|
|
b.WriteString(h)
|
|
b.WriteByte('\n')
|
|
}
|
|
return b.String()
|
|
}
|