package llmfs
import (
"context"
"fmt"
"io"
"strings"
"sync"
"github.com/NERVsystems/llm9p/internal/llm"
"github.com/NERVsystems/llm9p/internal/protocol"
)
// CompactFile allows manual compaction trigger
// Write anything to trigger compaction
// Read returns status ("ok" or "error: ...")
type CompactFile struct {
*protocol.BaseFile
client llm.Backend
mu sync.RWMutex
lastResult string
}
// NewCompactFile creates the compact file
func NewCompactFile(client llm.Backend) *CompactFile {
return &CompactFile{
BaseFile: protocol.NewBaseFile("compact", 0666),
client: client,
lastResult: "ready\n",
}
}
func (f *CompactFile) Read(p []byte, offset int64) (int, error) {
f.mu.RLock()
content := f.lastResult
f.mu.RUnlock()
if offset >= int64(len(content)) {
return 0, io.EOF
}
n := copy(p, content[offset:])
return n, nil
}
func (f *CompactFile) Write(p []byte, offset int64) (int, error) {
cmd := strings.TrimSpace(string(p))
if cmd == "" {
return len(p), nil
}
// Trigger compaction
err := f.client.Compact(context.Background())
f.mu.Lock()
if err != nil {
f.lastResult = fmt.Sprintf("error: %v\n", err)
} else {
tokens := f.client.TotalTokens()
limit := f.client.ContextLimit()
f.lastResult = fmt.Sprintf("ok: %d/%d\n", tokens, limit)
}
f.mu.Unlock()
return len(p), nil
}
func (f *CompactFile) Stat() protocol.Stat {
s := f.BaseFile.Stat()
f.mu.RLock()
s.Length = uint64(len(f.lastResult))
f.mu.RUnlock()
return s
}