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:
88
internal/tools/update.go
Normal file
88
internal/tools/update.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"strings"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"git.warky.dev/wdevs/amcs/internal/ai"
|
||||
"git.warky.dev/wdevs/amcs/internal/config"
|
||||
"git.warky.dev/wdevs/amcs/internal/metadata"
|
||||
"git.warky.dev/wdevs/amcs/internal/store"
|
||||
thoughttypes "git.warky.dev/wdevs/amcs/internal/types"
|
||||
)
|
||||
|
||||
type UpdateTool struct {
|
||||
store *store.DB
|
||||
provider ai.Provider
|
||||
capture config.CaptureConfig
|
||||
log *slog.Logger
|
||||
}
|
||||
|
||||
type UpdateInput struct {
|
||||
ID string `json:"id" jsonschema:"the thought id"`
|
||||
Content *string `json:"content,omitempty" jsonschema:"replacement content for the thought"`
|
||||
Metadata thoughttypes.ThoughtMetadata `json:"metadata,omitempty" jsonschema:"metadata fields to merge into the thought"`
|
||||
Project string `json:"project,omitempty" jsonschema:"optional project name or id to move the thought into"`
|
||||
}
|
||||
|
||||
type UpdateOutput struct {
|
||||
Thought thoughttypes.Thought `json:"thought"`
|
||||
}
|
||||
|
||||
func NewUpdateTool(db *store.DB, provider ai.Provider, capture config.CaptureConfig, log *slog.Logger) *UpdateTool {
|
||||
return &UpdateTool{store: db, provider: provider, capture: capture, log: log}
|
||||
}
|
||||
|
||||
func (t *UpdateTool) Handle(ctx context.Context, _ *mcp.CallToolRequest, in UpdateInput) (*mcp.CallToolResult, UpdateOutput, error) {
|
||||
id, err := parseUUID(in.ID)
|
||||
if err != nil {
|
||||
return nil, UpdateOutput{}, err
|
||||
}
|
||||
|
||||
current, err := t.store.GetThought(ctx, id)
|
||||
if err != nil {
|
||||
return nil, UpdateOutput{}, err
|
||||
}
|
||||
|
||||
content := current.Content
|
||||
embedding := current.Embedding
|
||||
mergedMetadata := current.Metadata
|
||||
projectID := current.ProjectID
|
||||
|
||||
if in.Content != nil {
|
||||
content = strings.TrimSpace(*in.Content)
|
||||
if content == "" {
|
||||
return nil, UpdateOutput{}, errInvalidInput("content must not be empty")
|
||||
}
|
||||
embedding, err = t.provider.Embed(ctx, content)
|
||||
if err != nil {
|
||||
return nil, UpdateOutput{}, err
|
||||
}
|
||||
extracted, extractErr := t.provider.ExtractMetadata(ctx, content)
|
||||
if extractErr != nil {
|
||||
t.log.Warn("metadata extraction failed during update, keeping current metadata", slog.String("error", extractErr.Error()))
|
||||
} else {
|
||||
mergedMetadata = metadata.Normalize(extracted, t.capture)
|
||||
}
|
||||
}
|
||||
|
||||
mergedMetadata = metadata.Merge(mergedMetadata, in.Metadata, t.capture)
|
||||
|
||||
if rawProject := strings.TrimSpace(in.Project); rawProject != "" {
|
||||
project, err := t.store.GetProject(ctx, rawProject)
|
||||
if err != nil {
|
||||
return nil, UpdateOutput{}, err
|
||||
}
|
||||
projectID = &project.ID
|
||||
}
|
||||
|
||||
updated, err := t.store.UpdateThought(ctx, id, content, embedding, mergedMetadata, projectID)
|
||||
if err != nil {
|
||||
return nil, UpdateOutput{}, err
|
||||
}
|
||||
|
||||
return nil, UpdateOutput{Thought: updated}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user