feat(llm): add LLM integration instructions and handler
* Serve LLM instructions at `/llm` * Include markdown content for memory instructions * Update README with LLM integration details * Add tests for LLM instructions handler * Modify database migrations to use GUIDs for thoughts and projects
This commit is contained in:
@@ -13,7 +13,9 @@ import (
|
||||
func (db *DB) InsertLink(ctx context.Context, link thoughttypes.ThoughtLink) error {
|
||||
_, err := db.pool.Exec(ctx, `
|
||||
insert into thought_links (from_id, to_id, relation)
|
||||
values ($1, $2, $3)
|
||||
select f.id, t.id, $3
|
||||
from thoughts f, thoughts t
|
||||
where f.guid = $1 and t.guid = $2
|
||||
`, link.FromID, link.ToID, link.Relation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("insert link: %w", err)
|
||||
@@ -23,15 +25,15 @@ func (db *DB) InsertLink(ctx context.Context, link thoughttypes.ThoughtLink) err
|
||||
|
||||
func (db *DB) LinkedThoughts(ctx context.Context, thoughtID uuid.UUID) ([]thoughttypes.LinkedThought, error) {
|
||||
rows, err := db.pool.Query(ctx, `
|
||||
select t.id, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at, l.relation, 'outgoing' as direction, l.created_at
|
||||
select t.guid, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at, l.relation, 'outgoing' as direction, l.created_at
|
||||
from thought_links l
|
||||
join thoughts t on t.id = l.to_id
|
||||
where l.from_id = $1
|
||||
where l.from_id = (select id from thoughts where guid = $1)
|
||||
union all
|
||||
select t.id, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at, l.relation, 'incoming' as direction, l.created_at
|
||||
select t.guid, t.content, t.metadata, t.project_id, t.archived_at, t.created_at, t.updated_at, l.relation, 'incoming' as direction, l.created_at
|
||||
from thought_links l
|
||||
join thoughts t on t.id = l.from_id
|
||||
where l.to_id = $1
|
||||
where l.to_id = (select id from thoughts where guid = $1)
|
||||
order by created_at desc
|
||||
`, thoughtID)
|
||||
if err != nil {
|
||||
|
||||
@@ -15,7 +15,7 @@ func (db *DB) CreateProject(ctx context.Context, name, description string) (thou
|
||||
row := db.pool.QueryRow(ctx, `
|
||||
insert into projects (name, description)
|
||||
values ($1, $2)
|
||||
returning id, name, description, created_at, last_active_at
|
||||
returning guid, name, description, created_at, last_active_at
|
||||
`, name, description)
|
||||
|
||||
var project thoughttypes.Project
|
||||
@@ -29,13 +29,13 @@ func (db *DB) GetProject(ctx context.Context, nameOrID string) (thoughttypes.Pro
|
||||
var row pgx.Row
|
||||
if parsedID, err := uuid.Parse(strings.TrimSpace(nameOrID)); err == nil {
|
||||
row = db.pool.QueryRow(ctx, `
|
||||
select id, name, description, created_at, last_active_at
|
||||
select guid, name, description, created_at, last_active_at
|
||||
from projects
|
||||
where id = $1
|
||||
where guid = $1
|
||||
`, parsedID)
|
||||
} else {
|
||||
row = db.pool.QueryRow(ctx, `
|
||||
select id, name, description, created_at, last_active_at
|
||||
select guid, name, description, created_at, last_active_at
|
||||
from projects
|
||||
where name = $1
|
||||
`, strings.TrimSpace(nameOrID))
|
||||
@@ -53,10 +53,10 @@ func (db *DB) GetProject(ctx context.Context, nameOrID string) (thoughttypes.Pro
|
||||
|
||||
func (db *DB) ListProjects(ctx context.Context) ([]thoughttypes.ProjectSummary, error) {
|
||||
rows, err := db.pool.Query(ctx, `
|
||||
select p.id, p.name, p.description, p.created_at, p.last_active_at, count(t.id) as thought_count
|
||||
select p.guid, p.name, p.description, p.created_at, p.last_active_at, count(t.id) as thought_count
|
||||
from projects p
|
||||
left join thoughts t on t.project_id = p.id and t.archived_at is null
|
||||
group by p.id
|
||||
left join thoughts t on t.project_id = p.guid and t.archived_at is null
|
||||
group by p.guid, p.name, p.description, p.created_at, p.last_active_at
|
||||
order by p.last_active_at desc, p.created_at desc
|
||||
`)
|
||||
if err != nil {
|
||||
@@ -79,7 +79,7 @@ func (db *DB) ListProjects(ctx context.Context) ([]thoughttypes.ProjectSummary,
|
||||
}
|
||||
|
||||
func (db *DB) TouchProject(ctx context.Context, id uuid.UUID) error {
|
||||
tag, err := db.pool.Exec(ctx, `update projects set last_active_at = now() where id = $1`, id)
|
||||
tag, err := db.pool.Exec(ctx, `update projects set last_active_at = now() where guid = $1`, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("touch project: %w", err)
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ func (db *DB) InsertThought(ctx context.Context, thought thoughttypes.Thought, e
|
||||
row := tx.QueryRow(ctx, `
|
||||
insert into thoughts (content, metadata, project_id)
|
||||
values ($1, $2::jsonb, $3)
|
||||
returning id, created_at, updated_at
|
||||
returning guid, created_at, updated_at
|
||||
`, thought.Content, metadata, thought.ProjectID)
|
||||
|
||||
created := thought
|
||||
@@ -123,7 +123,7 @@ func (db *DB) ListThoughts(ctx context.Context, filter thoughttypes.ListFilter)
|
||||
}
|
||||
|
||||
query := `
|
||||
select id, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
`
|
||||
if len(conditions) > 0 {
|
||||
@@ -209,9 +209,9 @@ func (db *DB) Stats(ctx context.Context) (thoughttypes.ThoughtStats, error) {
|
||||
|
||||
func (db *DB) GetThought(ctx context.Context, id uuid.UUID) (thoughttypes.Thought, error) {
|
||||
row := db.pool.QueryRow(ctx, `
|
||||
select id, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
select guid, content, metadata, project_id, archived_at, created_at, updated_at
|
||||
from thoughts
|
||||
where id = $1
|
||||
where guid = $1
|
||||
`, id)
|
||||
|
||||
var thought thoughttypes.Thought
|
||||
@@ -248,7 +248,7 @@ func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, e
|
||||
metadata = $3::jsonb,
|
||||
project_id = $4,
|
||||
updated_at = now()
|
||||
where id = $1
|
||||
where guid = $1
|
||||
`, id, content, metadataBytes, projectID)
|
||||
if err != nil {
|
||||
return thoughttypes.Thought{}, fmt.Errorf("update thought: %w", err)
|
||||
@@ -278,7 +278,7 @@ func (db *DB) UpdateThought(ctx context.Context, id uuid.UUID, content string, e
|
||||
}
|
||||
|
||||
func (db *DB) DeleteThought(ctx context.Context, id uuid.UUID) error {
|
||||
tag, err := db.pool.Exec(ctx, `delete from thoughts where id = $1`, id)
|
||||
tag, err := db.pool.Exec(ctx, `delete from thoughts where guid = $1`, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("delete thought: %w", err)
|
||||
}
|
||||
@@ -289,7 +289,7 @@ func (db *DB) DeleteThought(ctx context.Context, id uuid.UUID) error {
|
||||
}
|
||||
|
||||
func (db *DB) ArchiveThought(ctx context.Context, id uuid.UUID) error {
|
||||
tag, err := db.pool.Exec(ctx, `update thoughts set archived_at = now(), updated_at = now() where id = $1`, id)
|
||||
tag, err := db.pool.Exec(ctx, `update thoughts set archived_at = now(), updated_at = now() where guid = $1`, id)
|
||||
if err != nil {
|
||||
return fmt.Errorf("archive thought: %w", err)
|
||||
}
|
||||
@@ -322,14 +322,14 @@ func (db *DB) SearchSimilarThoughts(ctx context.Context, embedding []float32, em
|
||||
}
|
||||
if excludeID != nil {
|
||||
args = append(args, *excludeID)
|
||||
conditions = append(conditions, fmt.Sprintf("t.id <> $%d", len(args)))
|
||||
conditions = append(conditions, fmt.Sprintf("t.guid <> $%d", len(args)))
|
||||
}
|
||||
args = append(args, limit)
|
||||
|
||||
query := `
|
||||
select t.id, t.content, t.metadata, 1 - (e.embedding <=> $1) as similarity, t.created_at
|
||||
select t.guid, t.content, t.metadata, 1 - (e.embedding <=> $1) as similarity, t.created_at
|
||||
from thoughts t
|
||||
join embeddings e on e.thought_id = t.id
|
||||
join embeddings e on e.thought_id = t.guid
|
||||
where ` + strings.Join(conditions, " and ") + fmt.Sprintf(`
|
||||
order by e.embedding <=> $1
|
||||
limit $%d`, len(args))
|
||||
|
||||
Reference in New Issue
Block a user