feat(tools): implement CRUD operations for thoughts and projects

* Add tools for creating, retrieving, updating, and deleting thoughts.
* Implement project management tools for creating and listing projects.
* Introduce linking functionality between thoughts.
* Add search and recall capabilities for thoughts based on semantic queries.
* Implement statistics and summarization tools for thought analysis.
* Create database migrations for thoughts, projects, and links.
* Add helper functions for UUID parsing and project resolution.
This commit is contained in:
Hein
2026-03-24 15:38:59 +02:00
parent 64024193e9
commit 66370a7f0e
68 changed files with 4422 additions and 0 deletions

69
internal/store/links.go Normal file
View File

@@ -0,0 +1,69 @@
package store
import (
"context"
"encoding/json"
"fmt"
"github.com/google/uuid"
thoughttypes "git.warky.dev/wdevs/amcs/internal/types"
)
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)
`, link.FromID, link.ToID, link.Relation)
if err != nil {
return fmt.Errorf("insert link: %w", err)
}
return nil
}
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
from thought_links l
join thoughts t on t.id = l.to_id
where l.from_id = $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
from thought_links l
join thoughts t on t.id = l.from_id
where l.to_id = $1
order by created_at desc
`, thoughtID)
if err != nil {
return nil, fmt.Errorf("query linked thoughts: %w", err)
}
defer rows.Close()
links := make([]thoughttypes.LinkedThought, 0)
for rows.Next() {
var linked thoughttypes.LinkedThought
var metadataBytes []byte
if err := rows.Scan(
&linked.Thought.ID,
&linked.Thought.Content,
&metadataBytes,
&linked.Thought.ProjectID,
&linked.Thought.ArchivedAt,
&linked.Thought.CreatedAt,
&linked.Thought.UpdatedAt,
&linked.Relation,
&linked.Direction,
&linked.CreatedAt,
); err != nil {
return nil, fmt.Errorf("scan linked thought: %w", err)
}
if err := json.Unmarshal(metadataBytes, &linked.Thought.Metadata); err != nil {
return nil, fmt.Errorf("decode linked thought metadata: %w", err)
}
links = append(links, linked)
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("iterate linked thoughts: %w", err)
}
return links, nil
}