mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
dea06c391c
* Improve the web launcher and gateway integration across backend and frontend. - add runtime model availability checks for local and OAuth-backed models - support launcher-driven gateway host overrides and websocket URL resolution - add gateway log clearing and keep incremental log sync consistent after resets - migrate session history APIs to JSONL metadata-backed storage with legacy fallback - expose session titles and improve chat history loading and error handling - move shared backend runtime helpers into the web utils package - avoid blocking web startup when automatic onboard initialization fails - add backend tests covering gateway readiness, host resolution, models, logs, and sessions * feat(agent): add skills and tools management APIs and UI - add backend APIs to list, view, import, and delete skills - add tool status and toggle endpoints with dependency-aware config updates - add agent skills/tools pages, routes, sidebar entries, and i18n strings - add backend tests for the new skills and tools flows * chore(frontend): upgrade shadcn to 4.0.5 and refresh lockfile * chore(web): keep backend dist placeholder tracked
98 lines
2.3 KiB
Go
98 lines
2.3 KiB
Go
package api
|
|
|
|
import "sync"
|
|
|
|
// LogBuffer is a thread-safe ring buffer that stores the most recent N log lines.
|
|
// It supports incremental reads via LinesSince and tracks a runID that increments
|
|
// whenever the buffer is reset or cleared so clients can detect log history resets.
|
|
type LogBuffer struct {
|
|
mu sync.RWMutex
|
|
lines []string
|
|
cap int
|
|
total int // total lines ever appended in current run
|
|
runID int
|
|
}
|
|
|
|
// NewLogBuffer creates a LogBuffer with the given capacity.
|
|
func NewLogBuffer(capacity int) *LogBuffer {
|
|
return &LogBuffer{
|
|
lines: make([]string, 0, capacity),
|
|
cap: capacity,
|
|
}
|
|
}
|
|
|
|
// Append adds a line to the buffer. If the buffer is full, the oldest line is evicted.
|
|
func (b *LogBuffer) Append(line string) {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
if len(b.lines) < b.cap {
|
|
b.lines = append(b.lines, line)
|
|
} else {
|
|
b.lines[b.total%b.cap] = line
|
|
}
|
|
|
|
b.total++
|
|
}
|
|
|
|
// Reset clears the buffer and increments the runID. Call this when starting a new gateway process.
|
|
func (b *LogBuffer) Reset() {
|
|
b.mu.Lock()
|
|
defer b.mu.Unlock()
|
|
|
|
b.lines = b.lines[:0]
|
|
b.total = 0
|
|
b.runID++
|
|
}
|
|
|
|
// Clear removes all buffered lines and increments the runID so clients treat
|
|
// subsequent reads as a new log stream.
|
|
func (b *LogBuffer) Clear() {
|
|
b.Reset()
|
|
}
|
|
|
|
// LinesSince returns lines appended after the given offset, the current total count, and the runID.
|
|
// If offset >= total, no lines are returned. If offset is too old (evicted), all buffered lines are returned.
|
|
func (b *LogBuffer) LinesSince(offset int) (lines []string, total int, runID int) {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
total = b.total
|
|
runID = b.runID
|
|
|
|
if offset >= b.total {
|
|
return nil, total, runID
|
|
}
|
|
|
|
buffered := len(b.lines)
|
|
|
|
// How many new lines since offset
|
|
newCount := b.total - offset
|
|
if newCount > buffered {
|
|
newCount = buffered
|
|
}
|
|
|
|
result := make([]string, newCount)
|
|
|
|
if b.total <= b.cap {
|
|
// Buffer hasn't wrapped yet — simple slice
|
|
copy(result, b.lines[buffered-newCount:])
|
|
} else {
|
|
// Buffer has wrapped — read from ring
|
|
start := (b.total - newCount) % b.cap
|
|
for i := range newCount {
|
|
result[i] = b.lines[(start+i)%b.cap]
|
|
}
|
|
}
|
|
|
|
return result, total, runID
|
|
}
|
|
|
|
// RunID returns the current run identifier.
|
|
func (b *LogBuffer) RunID() int {
|
|
b.mu.RLock()
|
|
defer b.mu.RUnlock()
|
|
|
|
return b.runID
|
|
}
|