Release dec 2025 (#15)

* Resolves issue #13

- Switched model to bge-small-en-v1.5
- Added lazy re-embedding
- Added model version tracking per vector
- Added conversion of vectors to the new model

* Add lfs support to the workflow.

* Implements importance scoring with decay + voting #6

* Resolves issue #5 by marking observations as superseeded and scheduled for deletion

* Implement pattern detection #7

* Improve injections and observations accuracy

- Session start: Recent observations for project context (recency-based)
- User prompt: Semantically relevant observations (similarity-based with threshold)

* Added two stage retrieval with bi and cross encoder #8

* Implement query expansion and reformulation #9

* Knowledge graph and relationships ( resolves #4 )

- File Overlap Detection: Detects relationships when observations modify/read the same files
- Concept Overlap Detection: Detects relationships based on shared semantic concepts
- Type Progression Detection: Infers relationships from natural observation type progressions (e.g., discovery → bugfix = "fixes")
- Temporal Proximity Detection: Detects relationships between observations in the same session within 5 minutes
- Narrative Mention Detection: Detects explicit relationship language in narratives (e.g., "fixes", "depends on", "supersedes")

* Add visualisation of the relations to the dashboard.

* fixup! Add visualisation of the relations to the dashboard.

* Update documentation with new settings and screenshots.
This commit is contained in:
2025-12-19 17:57:11 +00:00
committed by GitHub
parent 48957a6c81
commit f79782a008
69 changed files with 43967 additions and 194 deletions
+51
View File
@@ -139,6 +139,16 @@ type Observation struct {
CreatedAt string `db:"created_at" json:"created_at"`
CreatedAtEpoch int64 `db:"created_at_epoch" json:"created_at_epoch"`
IsStale bool `db:"-" json:"is_stale,omitempty"`
// Importance scoring fields
ImportanceScore float64 `db:"importance_score" json:"importance_score"`
UserFeedback int `db:"user_feedback" json:"user_feedback"`
RetrievalCount int `db:"retrieval_count" json:"retrieval_count"`
LastRetrievedAt sql.NullInt64 `db:"last_retrieved_at_epoch" json:"last_retrieved_at_epoch,omitempty"`
ScoreUpdatedAt sql.NullInt64 `db:"score_updated_at_epoch" json:"score_updated_at_epoch,omitempty"`
// Conflict detection fields
IsSuperseded bool `db:"is_superseded" json:"is_superseded,omitempty"`
}
// ParsedObservation represents an observation parsed from SDK response XML.
@@ -205,6 +215,16 @@ type ObservationJSON struct {
CreatedAt string `json:"created_at"`
CreatedAtEpoch int64 `json:"created_at_epoch"`
IsStale bool `json:"is_stale,omitempty"`
// Importance scoring fields
ImportanceScore float64 `json:"importance_score"`
UserFeedback int `json:"user_feedback"`
RetrievalCount int `json:"retrieval_count"`
LastRetrievedAt int64 `json:"last_retrieved_at_epoch,omitempty"`
ScoreUpdatedAt int64 `json:"score_updated_at_epoch,omitempty"`
// Conflict detection fields
IsSuperseded bool `json:"is_superseded,omitempty"`
}
// MarshalJSON implements json.Marshaler for Observation.
@@ -225,6 +245,12 @@ func (o *Observation) MarshalJSON() ([]byte, error) {
CreatedAt: o.CreatedAt,
CreatedAtEpoch: o.CreatedAtEpoch,
IsStale: o.IsStale,
// Importance scoring fields
ImportanceScore: o.ImportanceScore,
UserFeedback: o.UserFeedback,
RetrievalCount: o.RetrievalCount,
// Conflict detection fields
IsSuperseded: o.IsSuperseded,
}
if o.Title.Valid {
j.Title = o.Title.String
@@ -238,6 +264,12 @@ func (o *Observation) MarshalJSON() ([]byte, error) {
if o.PromptNumber.Valid {
j.PromptNumber = o.PromptNumber.Int64
}
if o.LastRetrievedAt.Valid {
j.LastRetrievedAt = o.LastRetrievedAt.Int64
}
if o.ScoreUpdatedAt.Valid {
j.ScoreUpdatedAt = o.ScoreUpdatedAt.Int64
}
return json.Marshal(j)
}
@@ -268,9 +300,28 @@ func NewObservation(sdkSessionID, project string, parsed *ParsedObservation, pro
DiscoveryTokens: discoveryTokens,
CreatedAt: now.Format(time.RFC3339),
CreatedAtEpoch: now.UnixMilli(),
// Importance scoring: new observations start with score 1.0
ImportanceScore: 1.0,
UserFeedback: 0,
RetrievalCount: 0,
}
}
// ToMap converts the observation to a map for JSON response building.
// This allows adding extra fields like similarity scores.
func (o *Observation) ToMap() map[string]interface{} {
// Marshal to JSON then unmarshal to map (uses MarshalJSON for proper conversion)
data, err := json.Marshal(o)
if err != nil {
return map[string]interface{}{"id": o.ID, "error": err.Error()}
}
var result map[string]interface{}
if err := json.Unmarshal(data, &result); err != nil {
return map[string]interface{}{"id": o.ID, "error": err.Error()}
}
return result
}
// CheckStaleness checks if an observation is stale based on current file mtimes.
// Returns true if any tracked file has been modified since the observation was created.
func (o *Observation) CheckStaleness(currentMtimes map[string]int64) bool {