153 lines
5.0 KiB
Go
153 lines
5.0 KiB
Go
package tools
|
|
|
|
import (
|
|
"context"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/modelcontextprotocol/go-sdk/mcp"
|
|
|
|
"git.warky.dev/wdevs/amcs/internal/store"
|
|
thoughttypes "git.warky.dev/wdevs/amcs/internal/types"
|
|
)
|
|
|
|
type ThoughtLearningLinksTool struct {
|
|
store *store.DB
|
|
}
|
|
|
|
type LinkThoughtLearningInput struct {
|
|
ThoughtID string `json:"thought_id" jsonschema:"UUID of the thought to link"`
|
|
LearningID int64 `json:"learning_id" jsonschema:"numeric id of the learning to link"`
|
|
Relation string `json:"relation,omitempty" jsonschema:"relationship label, e.g. source, derived_from, related; defaults to source"`
|
|
}
|
|
|
|
type LinkThoughtLearningOutput struct {
|
|
Linked bool `json:"linked"`
|
|
}
|
|
|
|
type UnlinkThoughtLearningInput struct {
|
|
ThoughtID string `json:"thought_id" jsonschema:"UUID of the thought"`
|
|
LearningID int64 `json:"learning_id" jsonschema:"numeric id of the learning"`
|
|
}
|
|
|
|
type UnlinkThoughtLearningOutput struct {
|
|
Unlinked bool `json:"unlinked"`
|
|
}
|
|
|
|
type GetThoughtLearningsInput struct {
|
|
ThoughtID string `json:"thought_id" jsonschema:"UUID of the thought"`
|
|
}
|
|
|
|
type GetThoughtLearningsOutput struct {
|
|
Learnings []thoughttypes.LinkedLearning `json:"learnings"`
|
|
}
|
|
|
|
type GetLearningThoughtsInput struct {
|
|
LearningID int64 `json:"learning_id" jsonschema:"numeric id of the learning"`
|
|
}
|
|
|
|
type GetLearningThoughtsOutput struct {
|
|
Thoughts []thoughttypes.LinkedLearningThought `json:"thoughts"`
|
|
}
|
|
|
|
func NewThoughtLearningLinksTool(db *store.DB) *ThoughtLearningLinksTool {
|
|
return &ThoughtLearningLinksTool{store: db}
|
|
}
|
|
|
|
func (t *ThoughtLearningLinksTool) Link(ctx context.Context, _ *mcp.CallToolRequest, in LinkThoughtLearningInput) (*mcp.CallToolResult, LinkThoughtLearningOutput, error) {
|
|
if err := t.ensureConfigured(); err != nil {
|
|
return nil, LinkThoughtLearningOutput{}, err
|
|
}
|
|
|
|
thoughtGUID, err := parseUUID(in.ThoughtID)
|
|
if err != nil {
|
|
return nil, LinkThoughtLearningOutput{}, err
|
|
}
|
|
if in.LearningID <= 0 {
|
|
return nil, LinkThoughtLearningOutput{}, errRequiredField("learning_id")
|
|
}
|
|
relation := strings.TrimSpace(in.Relation)
|
|
if relation == "" {
|
|
relation = "source"
|
|
}
|
|
|
|
if _, err := t.store.GetThought(ctx, thoughtGUID); err != nil {
|
|
return nil, LinkThoughtLearningOutput{}, errEntityNotFound("thought", "thought_id", in.ThoughtID)
|
|
}
|
|
if _, err := t.store.GetLearning(ctx, in.LearningID); err != nil {
|
|
return nil, LinkThoughtLearningOutput{}, errEntityNotFound("learning", "learning_id", strconv.FormatInt(in.LearningID, 10))
|
|
}
|
|
|
|
if err := t.store.LinkThoughtLearning(ctx, thoughtGUID, in.LearningID, relation); err != nil {
|
|
return nil, LinkThoughtLearningOutput{}, err
|
|
}
|
|
return nil, LinkThoughtLearningOutput{Linked: true}, nil
|
|
}
|
|
|
|
func (t *ThoughtLearningLinksTool) Unlink(ctx context.Context, _ *mcp.CallToolRequest, in UnlinkThoughtLearningInput) (*mcp.CallToolResult, UnlinkThoughtLearningOutput, error) {
|
|
if err := t.ensureConfigured(); err != nil {
|
|
return nil, UnlinkThoughtLearningOutput{}, err
|
|
}
|
|
|
|
thoughtGUID, err := parseUUID(in.ThoughtID)
|
|
if err != nil {
|
|
return nil, UnlinkThoughtLearningOutput{}, err
|
|
}
|
|
if in.LearningID <= 0 {
|
|
return nil, UnlinkThoughtLearningOutput{}, errRequiredField("learning_id")
|
|
}
|
|
|
|
if err := t.store.UnlinkThoughtLearning(ctx, thoughtGUID, in.LearningID); err != nil {
|
|
return nil, UnlinkThoughtLearningOutput{}, err
|
|
}
|
|
return nil, UnlinkThoughtLearningOutput{Unlinked: true}, nil
|
|
}
|
|
|
|
func (t *ThoughtLearningLinksTool) GetThoughtLearnings(ctx context.Context, _ *mcp.CallToolRequest, in GetThoughtLearningsInput) (*mcp.CallToolResult, GetThoughtLearningsOutput, error) {
|
|
if err := t.ensureConfigured(); err != nil {
|
|
return nil, GetThoughtLearningsOutput{}, err
|
|
}
|
|
|
|
thoughtGUID, err := parseUUID(in.ThoughtID)
|
|
if err != nil {
|
|
return nil, GetThoughtLearningsOutput{}, err
|
|
}
|
|
|
|
if _, err := t.store.GetThought(ctx, thoughtGUID); err != nil {
|
|
return nil, GetThoughtLearningsOutput{}, errEntityNotFound("thought", "thought_id", in.ThoughtID)
|
|
}
|
|
|
|
learnings, err := t.store.GetLinkedLearnings(ctx, thoughtGUID)
|
|
if err != nil {
|
|
return nil, GetThoughtLearningsOutput{}, err
|
|
}
|
|
return nil, GetThoughtLearningsOutput{Learnings: learnings}, nil
|
|
}
|
|
|
|
func (t *ThoughtLearningLinksTool) GetLearningThoughts(ctx context.Context, _ *mcp.CallToolRequest, in GetLearningThoughtsInput) (*mcp.CallToolResult, GetLearningThoughtsOutput, error) {
|
|
if err := t.ensureConfigured(); err != nil {
|
|
return nil, GetLearningThoughtsOutput{}, err
|
|
}
|
|
|
|
if in.LearningID <= 0 {
|
|
return nil, GetLearningThoughtsOutput{}, errRequiredField("learning_id")
|
|
}
|
|
|
|
if _, err := t.store.GetLearning(ctx, in.LearningID); err != nil {
|
|
return nil, GetLearningThoughtsOutput{}, errEntityNotFound("learning", "learning_id", strconv.FormatInt(in.LearningID, 10))
|
|
}
|
|
|
|
thoughts, err := t.store.GetLinkedThoughtsForLearning(ctx, in.LearningID)
|
|
if err != nil {
|
|
return nil, GetLearningThoughtsOutput{}, err
|
|
}
|
|
return nil, GetLearningThoughtsOutput{Thoughts: thoughts}, nil
|
|
}
|
|
|
|
func (t *ThoughtLearningLinksTool) ensureConfigured() error {
|
|
if t == nil || t.store == nil {
|
|
return errInvalidInput("thought learning links tool is not configured")
|
|
}
|
|
return nil
|
|
}
|