package llmfs
import (
"fmt"
"io"
"github.com/NERVsystems/llm9p/internal/llm"
"github.com/NERVsystems/llm9p/internal/protocol"
)
// SessionUsageFile provides per-session token usage: /n/llm/N/usage
// Read returns "estimated_tokens/context_limit\n" (e.g., "42000/200000")
// Estimated tokens use a 4 chars/token heuristic over current message content.
type SessionUsageFile struct {
*protocol.BaseFile
sm *llm.SessionManager
id int
}
// NewSessionUsageFile creates a usage file for the given session.
func NewSessionUsageFile(sm *llm.SessionManager, id int) *SessionUsageFile {
return &SessionUsageFile{
BaseFile: protocol.NewBaseFile("usage", 0444),
sm: sm,
id: id,
}
}
// Read returns estimated token usage over context limit.
func (f *SessionUsageFile) Read(p []byte, offset int64) (int, error) {
estimated := f.sm.EstimatedContextTokens(f.id)
limit := f.sm.ContextLimit()
content := fmt.Sprintf("%d/%d\n", estimated, limit)
if offset >= int64(len(content)) {
return 0, io.EOF
}
return copy(p, content[offset:]), nil
}
// Write is not allowed.
func (f *SessionUsageFile) Write(p []byte, offset int64) (int, error) {
return 0, fmt.Errorf("usage is read-only")
}
// Stat returns the file's metadata.
func (f *SessionUsageFile) Stat() protocol.Stat {
s := f.BaseFile.Stat()
estimated := f.sm.EstimatedContextTokens(f.id)
limit := f.sm.ContextLimit()
s.Length = uint64(len(fmt.Sprintf("%d/%d\n", estimated, limit)))
return s
}