Documentation
¶
Index ¶
- type Client
- type EntityResolver
- type EntityResult
- type FactAction
- type FactExtractor
- type FactResolver
- type FactResult
- type MockGraphClient
- func (m *MockGraphClient) AppendEpisode(_ context.Context, factID, episodeID string) error
- func (m *MockGraphClient) AppendMemoryToFact(_ context.Context, factID, memoryID string) error
- func (m *MockGraphClient) Close() error
- func (m *MockGraphClient) EnsureSchema(_ context.Context) error
- func (m *MockGraphClient) GetEntity(_ context.Context, id string) (*models.Entity, error)
- func (m *MockGraphClient) GetFactsBetween(_ context.Context, sourceID, targetID string) ([]models.Fact, error)
- func (m *MockGraphClient) GetFactsForEntity(_ context.Context, entityID string) ([]models.Fact, error)
- func (m *MockGraphClient) GetMemoryFacts(_ context.Context, memoryID string) ([]models.Fact, error)
- func (m *MockGraphClient) Healthy(_ context.Context) bool
- func (m *MockGraphClient) InvalidateFact(_ context.Context, id string, expiredAt, invalidAt time.Time) error
- func (m *MockGraphClient) RecallByGraph(_ context.Context, _ string, _ []float32, _ int) ([]string, error)
- func (m *MockGraphClient) SearchEntities(_ context.Context, query string, _ []float32, _ string, limit int) ([]EntityResult, error)
- func (m *MockGraphClient) SearchFacts(_ context.Context, _ string, _ []float32, limit int) ([]FactResult, error)
- func (m *MockGraphClient) UpsertEntity(_ context.Context, entity models.Entity) error
- func (m *MockGraphClient) UpsertFact(_ context.Context, fact models.Fact) error
- type Neo4jClient
- func (c *Neo4jClient) AppendEpisode(ctx context.Context, factID, episodeID string) error
- func (c *Neo4jClient) AppendMemoryToFact(ctx context.Context, factID, memoryID string) error
- func (c *Neo4jClient) Close() error
- func (c *Neo4jClient) EnsureSchema(ctx context.Context) error
- func (c *Neo4jClient) GetEntity(ctx context.Context, id string) (*models.Entity, error)
- func (c *Neo4jClient) GetFactsBetween(ctx context.Context, sourceID, targetID string) ([]models.Fact, error)
- func (c *Neo4jClient) GetFactsForEntity(ctx context.Context, entityID string) ([]models.Fact, error)
- func (c *Neo4jClient) GetMemoryFacts(ctx context.Context, memoryID string) ([]models.Fact, error)
- func (c *Neo4jClient) Healthy(ctx context.Context) bool
- func (c *Neo4jClient) InvalidateFact(ctx context.Context, id string, expiredAt, invalidAt time.Time) error
- func (c *Neo4jClient) RecallByGraph(ctx context.Context, query string, embedding []float32, limit int) ([]string, error)
- func (c *Neo4jClient) SearchEntities(ctx context.Context, query string, _ []float32, project string, limit int) ([]EntityResult, error)
- func (c *Neo4jClient) SearchFacts(ctx context.Context, query string, _ []float32, limit int) ([]FactResult, error)
- func (c *Neo4jClient) UpsertEntity(ctx context.Context, entity models.Entity) error
- func (c *Neo4jClient) UpsertFact(ctx context.Context, fact models.Fact) error
- type SearchFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Client ¶
type Client interface {
// EnsureSchema creates indexes and constraints if they don't exist.
EnsureSchema(ctx context.Context) error
// UpsertEntity creates or updates an entity node.
UpsertEntity(ctx context.Context, entity models.Entity) error
// SearchEntities finds entities by fulltext + embedding similarity.
SearchEntities(ctx context.Context, query string, embedding []float32, project string, limit int) ([]EntityResult, error)
// GetEntity retrieves a single entity by ID.
GetEntity(ctx context.Context, id string) (*models.Entity, error)
// UpsertFact creates a RELATES_TO edge between two entities.
UpsertFact(ctx context.Context, fact models.Fact) error
// SearchFacts finds facts by hybrid search (BM25 + cosine + BFS).
SearchFacts(ctx context.Context, query string, embedding []float32, limit int) ([]FactResult, error)
// InvalidateFact sets ExpiredAt and InvalidAt on a fact (never deletes).
InvalidateFact(ctx context.Context, id string, expiredAt, invalidAt time.Time) error
// GetFactsBetween returns all active facts between two entities.
GetFactsBetween(ctx context.Context, sourceID, targetID string) ([]models.Fact, error)
// GetFactsForEntity returns all active facts involving an entity.
GetFactsForEntity(ctx context.Context, entityID string) ([]models.Fact, error)
// AppendEpisode adds an episode/session ID to a fact's episodes list.
AppendEpisode(ctx context.Context, factID, episodeID string) error
// AppendMemoryToFact adds a memory ID to a fact's source_memory_ids.
AppendMemoryToFact(ctx context.Context, factID, memoryID string) error
// GetMemoryFacts returns all facts derived from a given memory.
GetMemoryFacts(ctx context.Context, memoryID string) ([]models.Fact, error)
// RecallByGraph returns memory IDs relevant to a query via graph traversal.
RecallByGraph(ctx context.Context, query string, embedding []float32, limit int) ([]string, error)
// Healthy returns true if the graph database is reachable.
Healthy(ctx context.Context) bool
// Close releases resources.
Close() error
}
Client defines the interface for graph storage operations. Resolution logic lives in EntityResolver and FactResolver (separate types), matching the pattern where ConflictDetector is separate from Store.
type EntityResolver ¶
type EntityResolver struct {
// contains filtered or unexported fields
}
EntityResolver implements three-stage entity resolution: 1. Candidate retrieval via graph search 2. Deterministic fast-path (exact name, alias, embedding cosine) 3. Claude Haiku fallback for ambiguous cases
func NewEntityResolver ¶
func NewEntityResolver(graph Client, client llm.LLMClient, model string, threshold float64, maxCands int, logger *slog.Logger) *EntityResolver
NewEntityResolver creates a new EntityResolver. If client is nil, stage 3 (Claude fallback) is disabled and ambiguous entities are treated as new.
func (*EntityResolver) Resolve ¶
func (r *EntityResolver) Resolve(ctx context.Context, extracted models.Entity, embedding []float32, conversationContext string) (string, bool, error)
Resolve performs three-stage entity resolution and returns (resolvedID, isNew, err). If the entity matches an existing one, resolvedID is the existing entity's ID and isNew is false. Otherwise, resolvedID is the extracted entity's ID and isNew is true.
type EntityResult ¶
type EntityResult struct {
ID string `json:"id"`
Name string `json:"name"`
Type string `json:"type"`
Score float64 `json:"score"`
}
EntityResult is a search result from the graph entity index.
type FactAction ¶
type FactAction string
FactAction represents the resolution outcome for a new fact.
const ( FactActionInsert FactAction = "insert" // new fact, no duplicates FactActionSkip FactAction = "skip" // exact duplicate, append episode FactActionInvalidate FactAction = "invalidate" // contradicts existing, invalidate old )
type FactExtractor ¶
type FactExtractor struct {
// contains filtered or unexported fields
}
FactExtractor extracts relationship facts from conversation text using Claude.
func NewFactExtractor ¶
NewFactExtractor creates a new fact extractor backed by the Claude API.
func (*FactExtractor) Extract ¶
func (e *FactExtractor) Extract(ctx context.Context, content string, entityNames []string) ([]models.Fact, error)
Extract extracts relationship facts from conversation text. entityNames is the list of known entity names from the extraction step. On API error it logs a warning and returns (nil, nil) for graceful degradation.
NOTE: The returned facts have SourceEntityID and TargetEntityID set to entity NAMES (not UUIDs). The caller is responsible for resolving names to IDs after extraction, since Claude returns names and the ID mapping is external.
type FactResolver ¶
type FactResolver struct {
// contains filtered or unexported fields
}
FactResolver determines whether a new fact is a duplicate, contradiction, or new by comparing it against existing facts between the same entity pair.
func NewFactResolver ¶
func NewFactResolver(graph Client, client llm.LLMClient, model string, logger *slog.Logger) *FactResolver
NewFactResolver creates a new FactResolver. If client is nil, the resolver will treat all facts as new (graceful degradation).
type FactResult ¶
type FactResult struct {
ID string `json:"id"`
Fact string `json:"fact"`
SourceEntityID string `json:"source_entity_id"`
TargetEntityID string `json:"target_entity_id"`
SourceMemoryIDs []string `json:"source_memory_ids"`
Score float64 `json:"score"`
}
FactResult is a search result from the graph fact index.
func HybridSearch ¶
func HybridSearch(ctx context.Context, fns []SearchFunc, limit int) ([]FactResult, error)
HybridSearch runs multiple search functions in parallel and merges with RRF.
func RRFMerge ¶
func RRFMerge(lists [][]FactResult, limit int) []FactResult
RRFMerge implements Reciprocal Rank Fusion across multiple ranked lists. Each list contains FactResults sorted by their individual method score. Returns merged results sorted by combined RRF score, deduped by ID.
type MockGraphClient ¶
type MockGraphClient struct {
// contains filtered or unexported fields
}
MockGraphClient implements Client with in-memory maps for testing.
func NewMockGraphClient ¶
func NewMockGraphClient() *MockGraphClient
NewMockGraphClient creates a new MockGraphClient.
func (*MockGraphClient) AppendEpisode ¶
func (m *MockGraphClient) AppendEpisode(_ context.Context, factID, episodeID string) error
func (*MockGraphClient) AppendMemoryToFact ¶
func (m *MockGraphClient) AppendMemoryToFact(_ context.Context, factID, memoryID string) error
func (*MockGraphClient) Close ¶
func (m *MockGraphClient) Close() error
func (*MockGraphClient) EnsureSchema ¶
func (m *MockGraphClient) EnsureSchema(_ context.Context) error
func (*MockGraphClient) GetFactsBetween ¶
func (*MockGraphClient) GetFactsForEntity ¶
func (*MockGraphClient) GetMemoryFacts ¶
func (*MockGraphClient) InvalidateFact ¶
func (*MockGraphClient) RecallByGraph ¶
func (*MockGraphClient) SearchEntities ¶
func (m *MockGraphClient) SearchEntities(_ context.Context, query string, _ []float32, _ string, limit int) ([]EntityResult, error)
func (*MockGraphClient) SearchFacts ¶
func (m *MockGraphClient) SearchFacts(_ context.Context, _ string, _ []float32, limit int) ([]FactResult, error)
func (*MockGraphClient) UpsertEntity ¶
func (*MockGraphClient) UpsertFact ¶
type Neo4jClient ¶
type Neo4jClient struct {
// contains filtered or unexported fields
}
Neo4jClient implements Client using a Neo4j Bolt driver.
func NewNeo4jClient ¶
func NewNeo4jClient(ctx context.Context, uri, username, password, database string, logger *slog.Logger) (*Neo4jClient, error)
NewNeo4jClient creates a new Neo4jClient connected to the given Neo4j instance.
func (*Neo4jClient) AppendEpisode ¶
func (c *Neo4jClient) AppendEpisode(ctx context.Context, factID, episodeID string) error
AppendEpisode adds an episode/session ID to a fact's episodes list.
func (*Neo4jClient) AppendMemoryToFact ¶
func (c *Neo4jClient) AppendMemoryToFact(ctx context.Context, factID, memoryID string) error
AppendMemoryToFact adds a memory ID to a fact's source_memory_ids list.
func (*Neo4jClient) Close ¶
func (c *Neo4jClient) Close() error
Close releases the Neo4j driver resources.
func (*Neo4jClient) EnsureSchema ¶
func (c *Neo4jClient) EnsureSchema(ctx context.Context) error
EnsureSchema creates range indexes, fulltext indexes, and constraints.
func (*Neo4jClient) GetFactsBetween ¶
func (c *Neo4jClient) GetFactsBetween(ctx context.Context, sourceID, targetID string) ([]models.Fact, error)
GetFactsBetween returns all active facts between two entities.
func (*Neo4jClient) GetFactsForEntity ¶
func (c *Neo4jClient) GetFactsForEntity(ctx context.Context, entityID string) ([]models.Fact, error)
GetFactsForEntity returns all active facts involving an entity (as source or target).
func (*Neo4jClient) GetMemoryFacts ¶
GetMemoryFacts returns all facts derived from a given memory ID.
func (*Neo4jClient) Healthy ¶
func (c *Neo4jClient) Healthy(ctx context.Context) bool
Healthy returns true if the Neo4j database is reachable.
func (*Neo4jClient) InvalidateFact ¶
func (c *Neo4jClient) InvalidateFact(ctx context.Context, id string, expiredAt, invalidAt time.Time) error
InvalidateFact sets ExpiredAt and InvalidAt on a RELATES_TO relationship.
func (*Neo4jClient) RecallByGraph ¶
func (c *Neo4jClient) RecallByGraph(ctx context.Context, query string, embedding []float32, limit int) ([]string, error)
RecallByGraph returns memory IDs relevant to a query via fact search and extraction.
func (*Neo4jClient) SearchEntities ¶
func (c *Neo4jClient) SearchEntities(ctx context.Context, query string, _ []float32, project string, limit int) ([]EntityResult, error)
SearchEntities finds entities by fulltext search, optionally filtered by project.
func (*Neo4jClient) SearchFacts ¶
func (c *Neo4jClient) SearchFacts(ctx context.Context, query string, _ []float32, limit int) ([]FactResult, error)
SearchFacts performs a basic BM25 fulltext search over RELATES_TO relationships. The full hybrid search with RRF will be added in a later task (search.go).
func (*Neo4jClient) UpsertEntity ¶
UpsertEntity creates or updates an entity node with a dynamic type label.
func (*Neo4jClient) UpsertFact ¶
UpsertFact creates or updates a RELATES_TO relationship between two entities.
type SearchFunc ¶
type SearchFunc func(ctx context.Context, limit int) ([]FactResult, error)
SearchFunc is a function that returns a ranked list of fact results.