feat(tools): add maintenance and meal planning tools with CRUD operations
- Implement maintenance tool for adding, logging, and retrieving tasks - Create meals tool for managing recipes, meal plans, and shopping lists - Introduce reparse metadata tool for updating thought metadata - Add household knowledge, home maintenance, family calendar, meal planning, and professional CRM database migrations - Grant necessary permissions for new database tables
This commit is contained in:
137
internal/tools/maintenance.go
Normal file
137
internal/tools/maintenance.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
|
||||
"git.warky.dev/wdevs/amcs/internal/store"
|
||||
ext "git.warky.dev/wdevs/amcs/internal/types"
|
||||
)
|
||||
|
||||
type MaintenanceTool struct {
|
||||
store *store.DB
|
||||
}
|
||||
|
||||
func NewMaintenanceTool(db *store.DB) *MaintenanceTool {
|
||||
return &MaintenanceTool{store: db}
|
||||
}
|
||||
|
||||
// add_maintenance_task
|
||||
|
||||
type AddMaintenanceTaskInput struct {
|
||||
Name string `json:"name" jsonschema:"task name"`
|
||||
Category string `json:"category,omitempty" jsonschema:"e.g. hvac, plumbing, exterior, appliance, landscaping"`
|
||||
FrequencyDays *int `json:"frequency_days,omitempty" jsonschema:"recurrence interval in days; omit for one-time tasks"`
|
||||
NextDue *time.Time `json:"next_due,omitempty" jsonschema:"when the task is next due"`
|
||||
Priority string `json:"priority,omitempty" jsonschema:"low, medium, high, or urgent (default: medium)"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
}
|
||||
|
||||
type AddMaintenanceTaskOutput struct {
|
||||
Task ext.MaintenanceTask `json:"task"`
|
||||
}
|
||||
|
||||
func (t *MaintenanceTool) AddTask(ctx context.Context, _ *mcp.CallToolRequest, in AddMaintenanceTaskInput) (*mcp.CallToolResult, AddMaintenanceTaskOutput, error) {
|
||||
if strings.TrimSpace(in.Name) == "" {
|
||||
return nil, AddMaintenanceTaskOutput{}, errInvalidInput("name is required")
|
||||
}
|
||||
priority := strings.TrimSpace(in.Priority)
|
||||
if priority == "" {
|
||||
priority = "medium"
|
||||
}
|
||||
task, err := t.store.AddMaintenanceTask(ctx, ext.MaintenanceTask{
|
||||
Name: strings.TrimSpace(in.Name),
|
||||
Category: strings.TrimSpace(in.Category),
|
||||
FrequencyDays: in.FrequencyDays,
|
||||
NextDue: in.NextDue,
|
||||
Priority: priority,
|
||||
Notes: strings.TrimSpace(in.Notes),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, AddMaintenanceTaskOutput{}, err
|
||||
}
|
||||
return nil, AddMaintenanceTaskOutput{Task: task}, nil
|
||||
}
|
||||
|
||||
// log_maintenance
|
||||
|
||||
type LogMaintenanceInput struct {
|
||||
TaskID uuid.UUID `json:"task_id" jsonschema:"id of the maintenance task"`
|
||||
CompletedAt *time.Time `json:"completed_at,omitempty" jsonschema:"when the work was done (defaults to now)"`
|
||||
PerformedBy string `json:"performed_by,omitempty" jsonschema:"who did the work (self, vendor name, etc.)"`
|
||||
Cost *float64 `json:"cost,omitempty" jsonschema:"cost of the work"`
|
||||
Notes string `json:"notes,omitempty"`
|
||||
NextAction string `json:"next_action,omitempty" jsonschema:"recommended follow-up"`
|
||||
}
|
||||
|
||||
type LogMaintenanceOutput struct {
|
||||
Log ext.MaintenanceLog `json:"log"`
|
||||
}
|
||||
|
||||
func (t *MaintenanceTool) LogWork(ctx context.Context, _ *mcp.CallToolRequest, in LogMaintenanceInput) (*mcp.CallToolResult, LogMaintenanceOutput, error) {
|
||||
completedAt := time.Now()
|
||||
if in.CompletedAt != nil {
|
||||
completedAt = *in.CompletedAt
|
||||
}
|
||||
log, err := t.store.LogMaintenance(ctx, ext.MaintenanceLog{
|
||||
TaskID: in.TaskID,
|
||||
CompletedAt: completedAt,
|
||||
PerformedBy: strings.TrimSpace(in.PerformedBy),
|
||||
Cost: in.Cost,
|
||||
Notes: strings.TrimSpace(in.Notes),
|
||||
NextAction: strings.TrimSpace(in.NextAction),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, LogMaintenanceOutput{}, err
|
||||
}
|
||||
return nil, LogMaintenanceOutput{Log: log}, nil
|
||||
}
|
||||
|
||||
// get_upcoming_maintenance
|
||||
|
||||
type GetUpcomingMaintenanceInput struct {
|
||||
DaysAhead int `json:"days_ahead,omitempty" jsonschema:"how many days to look ahead (default: 30)"`
|
||||
}
|
||||
|
||||
type GetUpcomingMaintenanceOutput struct {
|
||||
Tasks []ext.MaintenanceTask `json:"tasks"`
|
||||
}
|
||||
|
||||
func (t *MaintenanceTool) GetUpcoming(ctx context.Context, _ *mcp.CallToolRequest, in GetUpcomingMaintenanceInput) (*mcp.CallToolResult, GetUpcomingMaintenanceOutput, error) {
|
||||
tasks, err := t.store.GetUpcomingMaintenance(ctx, in.DaysAhead)
|
||||
if err != nil {
|
||||
return nil, GetUpcomingMaintenanceOutput{}, err
|
||||
}
|
||||
if tasks == nil {
|
||||
tasks = []ext.MaintenanceTask{}
|
||||
}
|
||||
return nil, GetUpcomingMaintenanceOutput{Tasks: tasks}, nil
|
||||
}
|
||||
|
||||
// search_maintenance_history
|
||||
|
||||
type SearchMaintenanceHistoryInput struct {
|
||||
Query string `json:"query,omitempty" jsonschema:"search text matching task name or notes"`
|
||||
Category string `json:"category,omitempty" jsonschema:"filter by task category"`
|
||||
Start *time.Time `json:"start,omitempty" jsonschema:"filter logs completed on or after this date"`
|
||||
End *time.Time `json:"end,omitempty" jsonschema:"filter logs completed on or before this date"`
|
||||
}
|
||||
|
||||
type SearchMaintenanceHistoryOutput struct {
|
||||
Logs []ext.MaintenanceLogWithTask `json:"logs"`
|
||||
}
|
||||
|
||||
func (t *MaintenanceTool) SearchHistory(ctx context.Context, _ *mcp.CallToolRequest, in SearchMaintenanceHistoryInput) (*mcp.CallToolResult, SearchMaintenanceHistoryOutput, error) {
|
||||
logs, err := t.store.SearchMaintenanceHistory(ctx, in.Query, in.Category, in.Start, in.End)
|
||||
if err != nil {
|
||||
return nil, SearchMaintenanceHistoryOutput{}, err
|
||||
}
|
||||
if logs == nil {
|
||||
logs = []ext.MaintenanceLogWithTask{}
|
||||
}
|
||||
return nil, SearchMaintenanceHistoryOutput{Logs: logs}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user