mirror of
https://github.com/lukaszraczylo/claude-mnemonic.git
synced 2026-10-20 06:27:50 +00:00
fix: reorganize struct fields and config parameters for consistency
- [x] Reorder Config struct fields alphabetically and by related functionality - [x] Reorganize Observation model fields with archival fields grouped together - [x] Reorder ObservationStore fields to group related members - [x] Reorder Store struct fields with health check caching grouped - [x] Reorganize HealthInfo and PoolMetrics struct field order - [x] Reorder maintenance Service struct fields logically - [x] Reorganize MCP server handler parameter structs alphabetically - [x] Reorder pattern detector candidate tracking fields - [x] Reorganize search Manager struct fields by functionality - [x] Reorder vector Client struct fields with mutex protections grouped - [x] Reorganize handler request/response struct fields - [x] Update handlers_test.go to expect wrapped response format - [x] Reorder middleware TokenAuth and rate limiter fields - [x] Reorganize Service struct fields with grouped functionality - [x] Fix RateLimiter field ordering for clarity - [x] Reorder CircuitBreaker metrics fields
This commit is contained in:
@@ -484,11 +484,11 @@ type UpdateObservationRequest struct {
|
||||
Title *string `json:"title,omitempty"`
|
||||
Subtitle *string `json:"subtitle,omitempty"`
|
||||
Narrative *string `json:"narrative,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
Facts []string `json:"facts,omitempty"`
|
||||
Concepts []string `json:"concepts,omitempty"`
|
||||
FilesRead []string `json:"files_read,omitempty"`
|
||||
FilesModified []string `json:"files_modified,omitempty"`
|
||||
Scope *string `json:"scope,omitempty"`
|
||||
}
|
||||
|
||||
// handleUpdateObservation updates an existing observation.
|
||||
@@ -562,8 +562,8 @@ func (s *Service) handleUpdateObservation(w http.ResponseWriter, r *http.Request
|
||||
|
||||
// Broadcast update event
|
||||
s.sseBroadcaster.Broadcast(map[string]any{
|
||||
"type": "observation_updated",
|
||||
"id": id,
|
||||
"type": "observation_updated",
|
||||
"id": id,
|
||||
})
|
||||
|
||||
writeJSON(w, map[string]any{
|
||||
|
||||
@@ -29,23 +29,23 @@ type BulkImportRequest struct {
|
||||
|
||||
// BulkObservationInput represents a single observation in bulk import.
|
||||
type BulkObservationInput struct {
|
||||
Type string `json:"type"` // bugfix, feature, refactor, etc.
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title"`
|
||||
Subtitle string `json:"subtitle,omitempty"`
|
||||
Facts []string `json:"facts,omitempty"`
|
||||
Narrative string `json:"narrative,omitempty"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Facts []string `json:"facts,omitempty"`
|
||||
Concepts []string `json:"concepts,omitempty"`
|
||||
FilesRead []string `json:"files_read,omitempty"`
|
||||
FilesModified []string `json:"files_modified,omitempty"`
|
||||
Scope string `json:"scope,omitempty"` // project or global
|
||||
}
|
||||
|
||||
// BulkImportResponse contains the result of a bulk import operation.
|
||||
type BulkImportResponse struct {
|
||||
Errors []string `json:"errors,omitempty"`
|
||||
Imported int `json:"imported"`
|
||||
Failed int `json:"failed"`
|
||||
SkippedDuplicates int `json:"skipped_duplicates,omitempty"`
|
||||
Errors []string `json:"errors,omitempty"`
|
||||
}
|
||||
|
||||
// handleBulkImport handles bulk import of observations.
|
||||
@@ -208,10 +208,10 @@ func (s *Service) handleBulkImport(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// ArchiveRequest is the request body for archiving observations.
|
||||
type ArchiveRequest struct {
|
||||
IDs []int64 `json:"ids,omitempty"` // Specific IDs to archive
|
||||
Project string `json:"project,omitempty"` // Archive all in project older than max_age_days
|
||||
MaxAgeDays int `json:"max_age_days,omitempty"` // Only used with project
|
||||
Reason string `json:"reason,omitempty"` // Optional reason for archival
|
||||
Project string `json:"project,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
IDs []int64 `json:"ids,omitempty"`
|
||||
MaxAgeDays int `json:"max_age_days,omitempty"`
|
||||
}
|
||||
|
||||
// handleArchiveObservations archives observations by ID or by age.
|
||||
@@ -233,8 +233,8 @@ func (s *Service) handleArchiveObservations(w http.ResponseWriter, r *http.Reque
|
||||
if len(req.IDs) > 5 {
|
||||
// Use parallel archival for batches larger than 5
|
||||
type archiveResult struct {
|
||||
id int64
|
||||
err error
|
||||
id int64
|
||||
}
|
||||
results := make(chan archiveResult, len(req.IDs))
|
||||
|
||||
@@ -384,8 +384,8 @@ func (s *Service) handleExportObservations(w http.ResponseWriter, r *http.Reques
|
||||
if format == "" {
|
||||
format = "json"
|
||||
}
|
||||
scope := r.URL.Query().Get("scope") // project, global, or empty for all
|
||||
obsType := r.URL.Query().Get("type") // bugfix, feature, etc.
|
||||
scope := r.URL.Query().Get("scope") // project, global, or empty for all
|
||||
obsType := r.URL.Query().Get("type") // bugfix, feature, etc.
|
||||
limit := gorm.ParseLimitParamWithMax(r, 1000, 5000) // Higher limit for exports, capped at 5000
|
||||
|
||||
// Validate format
|
||||
@@ -491,10 +491,10 @@ func escapeCsvField(s string) string {
|
||||
|
||||
// BulkStatusRequest represents a request to update status for multiple observations.
|
||||
type BulkStatusRequest struct {
|
||||
IDs []int64 `json:"ids"`
|
||||
Action string `json:"action"` // "supersede", "archive", "set_feedback"
|
||||
Action string `json:"action"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
Feedback int `json:"feedback,omitempty"` // -1, 0, 1 for set_feedback action
|
||||
IDs []int64 `json:"ids"`
|
||||
Feedback int `json:"feedback,omitempty"`
|
||||
}
|
||||
|
||||
// handleBulkStatusUpdate updates status for multiple observations in one request.
|
||||
|
||||
@@ -25,10 +25,10 @@ type SessionInitRequest struct {
|
||||
|
||||
// SessionInitResponse is the response for session initialization.
|
||||
type SessionInitResponse struct {
|
||||
Reason string `json:"reason,omitempty"`
|
||||
SessionDBID int64 `json:"sessionDbId"`
|
||||
PromptNumber int `json:"promptNumber"`
|
||||
Skipped bool `json:"skipped,omitempty"`
|
||||
Reason string `json:"reason,omitempty"`
|
||||
}
|
||||
|
||||
// DuplicatePromptWindowSeconds is the time window for detecting duplicate prompt submissions.
|
||||
|
||||
@@ -66,6 +66,7 @@ func testService(t *testing.T) (*Service, func()) {
|
||||
cancel: cancel,
|
||||
startTime: time.Now(),
|
||||
retrievalStats: make(map[string]*RetrievalStats),
|
||||
cachedObsCounts: make(map[string]cachedCount),
|
||||
}
|
||||
|
||||
svc.setupRoutes()
|
||||
@@ -345,11 +346,13 @@ func TestHandleGetObservations_Limit(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
// Parse as generic JSON array since the model uses custom marshaling
|
||||
var observations []map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &observations)
|
||||
// Parse as object with observations key (API returns wrapped response)
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
observations, ok := response["observations"].([]interface{})
|
||||
require.True(t, ok, "expected observations array in response")
|
||||
assert.Len(t, observations, 10)
|
||||
}
|
||||
|
||||
@@ -1135,10 +1138,13 @@ func TestHandleGetObservations_DefaultLimit(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
var observations []map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &observations)
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
observations, ok := response["observations"].([]interface{})
|
||||
require.True(t, ok, "expected observations array in response")
|
||||
|
||||
// Should return default limit (100)
|
||||
assert.LessOrEqual(t, len(observations), DefaultObservationsLimit)
|
||||
}
|
||||
@@ -1159,10 +1165,12 @@ func TestHandleGetObservations_FilterByProject(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
var observations []map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &observations)
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
observations, ok := response["observations"].([]interface{})
|
||||
require.True(t, ok, "expected observations array in response")
|
||||
assert.Len(t, observations, 2)
|
||||
}
|
||||
|
||||
@@ -1412,10 +1420,12 @@ func TestHandleGetObservations(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
var observations []map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &observations)
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
observations, ok := response["observations"].([]interface{})
|
||||
require.True(t, ok, "expected observations array in response")
|
||||
assert.GreaterOrEqual(t, len(observations), 2)
|
||||
}
|
||||
|
||||
@@ -2697,10 +2707,13 @@ func TestHandleGetObservations_EmptyResult(t *testing.T) {
|
||||
|
||||
assert.Equal(t, http.StatusOK, rec.Code)
|
||||
|
||||
// Should return empty array, not null
|
||||
var obs []interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &obs)
|
||||
// Should return empty array within observations key, not null
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(rec.Body.Bytes(), &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
obs, ok := response["observations"].([]interface{})
|
||||
require.True(t, ok, "expected observations array in response")
|
||||
assert.NotNil(t, obs)
|
||||
}
|
||||
|
||||
|
||||
@@ -91,12 +91,10 @@ func MaxBodySize(maxBytes int64) func(http.Handler) http.Handler {
|
||||
// TokenAuth provides simple token-based authentication for localhost services.
|
||||
// The token is generated at startup and must be provided in the X-Auth-Token header.
|
||||
type TokenAuth struct {
|
||||
token string
|
||||
enabled bool
|
||||
mu sync.RWMutex
|
||||
|
||||
// ExemptPaths are paths that don't require authentication (e.g., health checks)
|
||||
ExemptPaths map[string]bool
|
||||
token string
|
||||
mu sync.RWMutex
|
||||
enabled bool
|
||||
}
|
||||
|
||||
// NewTokenAuth creates a new TokenAuth with a randomly generated token.
|
||||
@@ -176,7 +174,7 @@ func (ta *TokenAuth) Middleware(next http.Handler) http.Handler {
|
||||
// It wraps the base per-client rate limiter with additional per-operation limits.
|
||||
type ExpensiveOperationLimiter struct {
|
||||
// Track last execution time per operation type
|
||||
lastRebuild int64 // Unix timestamp
|
||||
lastRebuild int64 // Unix timestamp
|
||||
rebuildCooldown int64 // Minimum seconds between rebuilds
|
||||
|
||||
mu sync.Mutex
|
||||
|
||||
@@ -42,8 +42,8 @@ func TestSecurityHeaders_CORS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
origin string
|
||||
expectCORS bool
|
||||
expectedOrigin string
|
||||
expectCORS bool
|
||||
}{
|
||||
{
|
||||
name: "localhost:37778 origin allowed",
|
||||
|
||||
@@ -9,13 +9,13 @@ import (
|
||||
|
||||
// RateLimiter implements a token bucket rate limiter.
|
||||
type RateLimiter struct {
|
||||
rate float64 // tokens per second
|
||||
burst int // maximum burst size
|
||||
mu sync.Mutex // protects following fields
|
||||
tokens float64 // current tokens
|
||||
lastUpdate time.Time // last token update time
|
||||
requests int64 // total requests
|
||||
rejected int64 // rejected requests
|
||||
lastUpdate time.Time
|
||||
rate float64
|
||||
burst int
|
||||
tokens float64
|
||||
requests int64
|
||||
rejected int64
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// LastUpdateTime returns the last update time.
|
||||
@@ -77,12 +77,12 @@ func (rl *RateLimiter) Stats() map[string]any {
|
||||
defer rl.mu.Unlock()
|
||||
|
||||
return map[string]any{
|
||||
"rate": rl.rate,
|
||||
"burst": rl.burst,
|
||||
"current_tokens": rl.tokens,
|
||||
"total_requests": rl.requests,
|
||||
"rejected": rl.rejected,
|
||||
"rejection_rate": float64(rl.rejected) / max(float64(rl.requests), 1),
|
||||
"rate": rl.rate,
|
||||
"burst": rl.burst,
|
||||
"current_tokens": rl.tokens,
|
||||
"total_requests": rl.requests,
|
||||
"rejected": rl.rejected,
|
||||
"rejection_rate": float64(rl.rejected) / max(float64(rl.requests), 1),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,14 +102,13 @@ func RateLimitMiddleware(limiter *RateLimiter) func(http.Handler) http.Handler {
|
||||
|
||||
// PerClientRateLimiter implements per-client rate limiting.
|
||||
type PerClientRateLimiter struct {
|
||||
rate float64
|
||||
burst int
|
||||
clients map[string]*RateLimiter
|
||||
mu sync.Mutex
|
||||
// Cleanup settings
|
||||
lastCleanup time.Time
|
||||
clients map[string]*RateLimiter
|
||||
rate float64
|
||||
burst int
|
||||
cleanupInterval time.Duration
|
||||
maxIdleTime time.Duration
|
||||
lastCleanup time.Time
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// NewPerClientRateLimiter creates a new per-client rate limiter.
|
||||
|
||||
@@ -26,11 +26,11 @@ import (
|
||||
|
||||
// CircuitBreaker implements a simple circuit breaker pattern for CLI calls.
|
||||
type CircuitBreaker struct {
|
||||
failures int64 // Current failure count
|
||||
lastFailure int64 // Unix timestamp of last failure
|
||||
threshold int64 // Number of failures before opening
|
||||
resetTimeout int64 // Seconds to wait before trying again
|
||||
state int32 // 0=closed, 1=open, 2=half-open
|
||||
failures int64 // Current failure count
|
||||
lastFailure int64 // Unix timestamp of last failure
|
||||
threshold int64 // Number of failures before opening
|
||||
resetTimeout int64 // Seconds to wait before trying again
|
||||
state int32 // 0=closed, 1=open, 2=half-open
|
||||
}
|
||||
|
||||
const (
|
||||
@@ -100,12 +100,12 @@ func (cb *CircuitBreaker) State() string {
|
||||
|
||||
// CircuitBreakerMetrics contains metrics about the circuit breaker state.
|
||||
type CircuitBreakerMetrics struct {
|
||||
State string `json:"state"`
|
||||
Failures int64 `json:"failures"`
|
||||
Threshold int64 `json:"threshold"`
|
||||
ResetTimeoutSecs int64 `json:"reset_timeout_secs"`
|
||||
LastFailureUnix int64 `json:"last_failure_unix,omitempty"`
|
||||
SecondsUntilReset int64 `json:"seconds_until_reset,omitempty"`
|
||||
State string `json:"state"`
|
||||
Failures int64 `json:"failures"`
|
||||
Threshold int64 `json:"threshold"`
|
||||
ResetTimeoutSecs int64 `json:"reset_timeout_secs"`
|
||||
LastFailureUnix int64 `json:"last_failure_unix,omitempty"`
|
||||
SecondsUntilReset int64 `json:"seconds_until_reset,omitempty"`
|
||||
}
|
||||
|
||||
// Metrics returns the current metrics of the circuit breaker.
|
||||
@@ -277,8 +277,8 @@ func NewProcessor(observationStore *gorm.ObservationStore, summaryStore *gorm.Su
|
||||
observationStore: observationStore,
|
||||
summaryStore: summaryStore,
|
||||
sem: make(chan struct{}, MaxConcurrentCLICalls),
|
||||
circuitBreaker: NewCircuitBreaker(5, 60), // Open after 5 failures, reset after 60s
|
||||
deduplicator: NewRequestDeduplicator(300, 1000), // 5-minute TTL, 1000 max entries
|
||||
circuitBreaker: NewCircuitBreaker(5, 60), // Open after 5 failures, reset after 60s
|
||||
deduplicator: NewRequestDeduplicator(300, 1000), // 5-minute TTL, 1000 max entries
|
||||
vectorSyncChan: make(chan *models.Observation, MaxVectorSyncWorkers*2), // Buffered channel
|
||||
vectorSyncDone: make(chan struct{}),
|
||||
}, nil
|
||||
|
||||
+77
-118
@@ -78,16 +78,16 @@ func retryWithBackoff(ctx context.Context, maxRetries int, initialBackoff time.D
|
||||
|
||||
// RetrievalStats tracks observation retrieval metrics.
|
||||
type RetrievalStats struct {
|
||||
TotalRequests int64 // Total retrieval requests (inject + search)
|
||||
ObservationsServed int64 // Observations returned to clients
|
||||
VerifiedStale int64 // Stale observations that passed verification
|
||||
DeletedInvalid int64 // Invalid observations deleted
|
||||
SearchRequests int64 // Semantic search requests
|
||||
ContextInjections int64 // Session-start context injections
|
||||
StaleExcluded int64 // Observations excluded due to staleness check
|
||||
FreshCount int64 // Observations that passed staleness check
|
||||
DuplicatesRemoved int64 // Observations removed by clustering
|
||||
LastUpdated int64 // Unix timestamp of last update (atomic)
|
||||
TotalRequests int64 // Total retrieval requests (inject + search)
|
||||
ObservationsServed int64 // Observations returned to clients
|
||||
VerifiedStale int64 // Stale observations that passed verification
|
||||
DeletedInvalid int64 // Invalid observations deleted
|
||||
SearchRequests int64 // Semantic search requests
|
||||
ContextInjections int64 // Session-start context injections
|
||||
StaleExcluded int64 // Observations excluded due to staleness check
|
||||
FreshCount int64 // Observations that passed staleness check
|
||||
DuplicatesRemoved int64 // Observations removed by clustering
|
||||
LastUpdated int64 // Unix timestamp of last update (atomic)
|
||||
}
|
||||
|
||||
// maxRetrievalStatsProjects limits the number of projects tracked to prevent unbounded memory growth.
|
||||
@@ -101,132 +101,91 @@ const maxRecentQueries = 100
|
||||
|
||||
// Service is the main worker service orchestrator.
|
||||
type Service struct {
|
||||
// Version of the worker binary
|
||||
version string
|
||||
|
||||
// Configuration
|
||||
config *config.Config
|
||||
|
||||
// Database
|
||||
store *gorm.Store
|
||||
sessionStore *gorm.SessionStore
|
||||
observationStore *gorm.ObservationStore
|
||||
summaryStore *gorm.SummaryStore
|
||||
promptStore *gorm.PromptStore
|
||||
conflictStore *gorm.ConflictStore
|
||||
patternStore *gorm.PatternStore
|
||||
relationStore *gorm.RelationStore
|
||||
|
||||
// Pattern detection
|
||||
patternDetector *pattern.Detector
|
||||
|
||||
// Domain services
|
||||
sessionManager *session.Manager
|
||||
sseBroadcaster *sse.Broadcaster
|
||||
processor *sdk.Processor
|
||||
|
||||
// Vector database (sqlite-vec with local embeddings)
|
||||
embedSvc *embedding.Service
|
||||
vectorClient *sqlitevec.Client
|
||||
vectorSync *sqlitevec.Sync
|
||||
|
||||
// Cross-encoder reranking (for improved search relevance)
|
||||
reranker *reranking.Service
|
||||
|
||||
// Query expansion (for improved search recall)
|
||||
queryExpander *expansion.Expander
|
||||
|
||||
// Importance scoring
|
||||
scoreCalculator *scoring.Calculator
|
||||
recalculator *scoring.Recalculator
|
||||
|
||||
// HTTP server
|
||||
router *chi.Mux
|
||||
server *http.Server
|
||||
startTime time.Time
|
||||
|
||||
// Retrieval statistics (per-project)
|
||||
retrievalStats map[string]*RetrievalStats
|
||||
retrievalStatsMu sync.RWMutex
|
||||
|
||||
// Lifecycle
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
wg sync.WaitGroup
|
||||
|
||||
// Initialization state (for deferred init)
|
||||
ready atomic.Bool
|
||||
initError error
|
||||
initMu sync.RWMutex
|
||||
|
||||
// Background verification queue for stale observations
|
||||
staleQueue chan staleVerifyRequest
|
||||
staleQueueOnce sync.Once
|
||||
|
||||
// File watchers for auto-recreation on deletion
|
||||
dbWatcher *watcher.Watcher
|
||||
configWatcher *watcher.Watcher
|
||||
|
||||
// Self-updater
|
||||
updater *update.Updater
|
||||
|
||||
// Rate limiting
|
||||
rateLimiter *PerClientRateLimiter
|
||||
expensiveOpLimiter *ExpensiveOperationLimiter
|
||||
bulkOpLimiter *BulkOperationLimiter
|
||||
|
||||
// Rebuild status tracking
|
||||
rebuildStatus *RebuildStatus
|
||||
rebuildStatusMu sync.RWMutex
|
||||
|
||||
// Recent search query tracking (circular buffer for O(1) insertion)
|
||||
recentQueriesBuf [maxRecentQueries]RecentSearchQuery // fixed-size circular buffer
|
||||
recentQueriesHead int // index of most recent (newest)
|
||||
recentQueriesLen int // current number of items
|
||||
recentQueriesMu sync.RWMutex
|
||||
|
||||
// Stats caching to reduce database load
|
||||
cachedObsCounts map[string]cachedCount // per-project observation counts
|
||||
cachedObsCountsMu sync.RWMutex
|
||||
statsCacheTTL time.Duration
|
||||
|
||||
// Vector sync worker pool - limits concurrent vector sync goroutines
|
||||
vectorSyncSem chan struct{} // semaphore for rate limiting
|
||||
startTime time.Time
|
||||
ctx context.Context
|
||||
initError error
|
||||
server *http.Server
|
||||
reranker *reranking.Service
|
||||
observationStore *gorm.ObservationStore
|
||||
summaryStore *gorm.SummaryStore
|
||||
promptStore *gorm.PromptStore
|
||||
conflictStore *gorm.ConflictStore
|
||||
patternStore *gorm.PatternStore
|
||||
relationStore *gorm.RelationStore
|
||||
patternDetector *pattern.Detector
|
||||
sessionManager *session.Manager
|
||||
sseBroadcaster *sse.Broadcaster
|
||||
processor *sdk.Processor
|
||||
embedSvc *embedding.Service
|
||||
vectorClient *sqlitevec.Client
|
||||
vectorSync *sqlitevec.Sync
|
||||
vectorSyncSem chan struct{}
|
||||
queryExpander *expansion.Expander
|
||||
scoreCalculator *scoring.Calculator
|
||||
recalculator *scoring.Recalculator
|
||||
router *chi.Mux
|
||||
store *gorm.Store
|
||||
retrievalStats map[string]*RetrievalStats
|
||||
sessionStore *gorm.SessionStore
|
||||
cancel context.CancelFunc
|
||||
cachedObsCounts map[string]cachedCount
|
||||
config *config.Config
|
||||
rebuildStatus *RebuildStatus
|
||||
staleQueue chan staleVerifyRequest
|
||||
bulkOpLimiter *BulkOperationLimiter
|
||||
dbWatcher *watcher.Watcher
|
||||
configWatcher *watcher.Watcher
|
||||
updater *update.Updater
|
||||
rateLimiter *PerClientRateLimiter
|
||||
expensiveOpLimiter *ExpensiveOperationLimiter
|
||||
version string
|
||||
recentQueriesBuf [maxRecentQueries]RecentSearchQuery
|
||||
wg sync.WaitGroup
|
||||
recentQueriesLen int
|
||||
recentQueriesHead int
|
||||
statsCacheTTL time.Duration
|
||||
initMu sync.RWMutex
|
||||
rebuildStatusMu sync.RWMutex
|
||||
retrievalStatsMu sync.RWMutex
|
||||
recentQueriesMu sync.RWMutex
|
||||
cachedObsCountsMu sync.RWMutex
|
||||
staleQueueOnce sync.Once
|
||||
ready atomic.Bool
|
||||
}
|
||||
|
||||
// cachedCount stores a cached count value with expiration.
|
||||
type cachedCount struct {
|
||||
count int
|
||||
timestamp time.Time
|
||||
count int
|
||||
}
|
||||
|
||||
// RebuildStatus tracks the progress of vector rebuild operations.
|
||||
type RebuildStatus struct {
|
||||
InProgress bool `json:"in_progress"`
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
Phase string `json:"phase,omitempty"` // "observations", "summaries", "prompts", "complete"
|
||||
TotalSynced int `json:"total_synced"`
|
||||
TotalErrors int `json:"total_errors"`
|
||||
CurrentPhase int `json:"current_phase"` // 1, 2, 3 for the three phases
|
||||
TotalPhases int `json:"total_phases"` // 3
|
||||
ElapsedMs int64 `json:"elapsed_ms,omitempty"`
|
||||
EstimatedPct float64 `json:"estimated_pct,omitempty"` // 0-100
|
||||
StartTime time.Time `json:"start_time,omitempty"`
|
||||
Phase string `json:"phase,omitempty"`
|
||||
TotalSynced int `json:"total_synced"`
|
||||
TotalErrors int `json:"total_errors"`
|
||||
CurrentPhase int `json:"current_phase"`
|
||||
TotalPhases int `json:"total_phases"`
|
||||
ElapsedMs int64 `json:"elapsed_ms,omitempty"`
|
||||
EstimatedPct float64 `json:"estimated_pct,omitempty"`
|
||||
InProgress bool `json:"in_progress"`
|
||||
}
|
||||
|
||||
// staleVerifyRequest represents a request to verify a stale observation in background
|
||||
type staleVerifyRequest struct {
|
||||
observationID int64
|
||||
cwd string
|
||||
observationID int64
|
||||
}
|
||||
|
||||
// RecentSearchQuery tracks a search query for analytics.
|
||||
type RecentSearchQuery struct {
|
||||
Query string `json:"query"`
|
||||
Project string `json:"project,omitempty"`
|
||||
Type string `json:"type,omitempty"` // observations, summaries, prompts
|
||||
Results int `json:"results"`
|
||||
UsedVector bool `json:"used_vector"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Query string `json:"query"`
|
||||
Project string `json:"project,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Results int `json:"results"`
|
||||
UsedVector bool `json:"used_vector"`
|
||||
}
|
||||
|
||||
// asyncVectorSync executes a vector sync operation with rate limiting.
|
||||
|
||||
Reference in New Issue
Block a user