mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-07-28 16:20:39 +00:00
- Sigma.js graph: restore doc_type coloring (revert Louvain community detection) - Fix animation flash after FA2 layout finishes by removing post-processing camera reset and redundant noverlap/compactOrphans in stopLayout - Fix vault tree "Load more" state bug when filtering by doc_type: add treeVersion counter to force re-mount and reset auto-expand state - Fix meta map loss: loadRoot now merges instead of replacing, preserving subtree entries from previous loadSubtree calls - Add compact graph DTO endpoints and hooks for KG and vault graphs - Add semantic zoom tiers, adaptive FA2 settings, and node sizing
106 lines
2.7 KiB
Go
106 lines
2.7 KiB
Go
//go:build sqlite || sqliteonly
|
|
|
|
package sqlitestore
|
|
|
|
import (
|
|
"context"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// SQLiteKGGraphStore implements store.KGGraphStore backed by SQLite.
|
|
type SQLiteKGGraphStore struct {
|
|
db *sql.DB
|
|
}
|
|
|
|
// NewSQLiteKGGraphStore creates a new SQLite-backed KG graph store.
|
|
func NewSQLiteKGGraphStore(db *sql.DB) *SQLiteKGGraphStore {
|
|
return &SQLiteKGGraphStore{db: db}
|
|
}
|
|
|
|
// ListKGGraphNodes returns lightweight KG entities for graph visualization.
|
|
func (s *SQLiteKGGraphStore) ListKGGraphNodes(ctx context.Context, agentID, userID string, limit int) ([]store.KGGraphNode, int, error) {
|
|
if limit <= 0 {
|
|
limit = 2000
|
|
}
|
|
if limit > 10000 {
|
|
limit = 10000
|
|
}
|
|
|
|
q := `SELECT id, name, entity_type, confidence
|
|
FROM kg_entities WHERE agent_id = ? AND valid_until IS NULL`
|
|
args := []any{agentID}
|
|
|
|
userClause, userArgs := kgUserClauseFor(ctx, userID)
|
|
if userClause != "" {
|
|
q += userClause
|
|
args = append(args, userArgs...)
|
|
}
|
|
|
|
q += " ORDER BY updated_at DESC LIMIT ?"
|
|
args = append(args, limit)
|
|
|
|
rows, err := s.db.QueryContext(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph nodes: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var nodes []store.KGGraphNode
|
|
for rows.Next() {
|
|
var n store.KGGraphNode
|
|
if err := rows.Scan(&n.ID, &n.Name, &n.EntityType, &n.Confidence); err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph nodes scan: %w", err)
|
|
}
|
|
nodes = append(nodes, n)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph nodes rows: %w", err)
|
|
}
|
|
return nodes, len(nodes), nil
|
|
}
|
|
|
|
// ListKGGraphEdges returns lightweight KG relations for graph visualization.
|
|
func (s *SQLiteKGGraphStore) ListKGGraphEdges(ctx context.Context, agentID, userID string, limit int) ([]store.KGGraphEdge, int, error) {
|
|
if limit <= 0 {
|
|
limit = 6000
|
|
}
|
|
if limit > 30000 {
|
|
limit = 30000
|
|
}
|
|
|
|
q := `SELECT id, source_entity_id, target_entity_id, relation_type
|
|
FROM kg_relations WHERE agent_id = ? AND valid_until IS NULL`
|
|
args := []any{agentID}
|
|
|
|
userClause, userArgs := kgUserClauseFor(ctx, userID)
|
|
if userClause != "" {
|
|
q += userClause
|
|
args = append(args, userArgs...)
|
|
}
|
|
|
|
q += " LIMIT ?"
|
|
args = append(args, limit)
|
|
|
|
rows, err := s.db.QueryContext(ctx, q, args...)
|
|
if err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph edges: %w", err)
|
|
}
|
|
defer rows.Close()
|
|
|
|
var edges []store.KGGraphEdge
|
|
for rows.Next() {
|
|
var e store.KGGraphEdge
|
|
if err := rows.Scan(&e.ID, &e.SourceID, &e.TargetID, &e.RelationType); err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph edges scan: %w", err)
|
|
}
|
|
edges = append(edges, e)
|
|
}
|
|
if err := rows.Err(); err != nil {
|
|
return nil, 0, fmt.Errorf("kg graph edges rows: %w", err)
|
|
}
|
|
return edges, len(edges), nil
|
|
}
|