/* * Copyright 2025 CloudWeGo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package task import ( "context" "fmt" "github.com/cloudwego/eino/components/tool" "github.com/cloudwego/eino/components/tool/utils" "github.com/google/uuid" ) type Action string const ( ActionAdd Action = "add" ActionGet Action = "get" ActionUpdate Action = "update" ActionDelete Action = "delete" ActionList Action = "list" ) type Task struct { ID string `json:"id" jsonschema:"description:id of the task"` Title string `json:"title" jsonschema:"description:title of the task"` Content string `json:"content" jsonschema:"description:content of the task"` Completed bool `json:"completed" jsonschema:"description:completed status of the task"` Deadline string `json:"deadline" jsonschema:"description:deadline of the task"` IsDeleted bool `json:"is_deleted" jsonschema:"-"` CreatedAt string `json:"created_at" jsonschema:"description:created time of the task"` } type TaskRequest struct { Action Action `json:"action" jsonschema:"description:action to perform, enum:add,update,delete,list"` Task *Task `json:"task" jsonschema:"description:task to add, update, or delete"` List *ListParams `json:"list" jsonschema:"description:list parameters"` } type ListParams struct { Query string `json:"query" jsonschema:"description:query to search"` IsDone *bool `json:"is_done" jsonschema:"description:filter by completed status"` Limit *int `json:"limit" jsonschema:"description:limit the number of results"` } type TaskResponse struct { Status string `json:"status" jsonschema:"description:status of the response"` TaskList []*Task `json:"task_list" jsonschema:"description:list of tasks"` Error string `json:"error" jsonschema:"description:error message"` } type TaskToolImpl struct { config *TaskToolConfig } type TaskToolConfig struct { Storage *Storage } func defaultTaskToolConfig(ctx context.Context) (*TaskToolConfig, error) { config := &TaskToolConfig{ Storage: GetDefaultStorage(), } return config, nil } func NewTaskToolImpl(ctx context.Context, config *TaskToolConfig) (*TaskToolImpl, error) { var err error if config == nil { config, err = defaultTaskToolConfig(ctx) if err != nil { return nil, err } } if config.Storage == nil { return nil, fmt.Errorf("storage cannot be empty") } t := &TaskToolImpl{config: config} return t, nil } func NewTaskTool(ctx context.Context, config *TaskToolConfig) (tn tool.BaseTool, err error) { if config == nil { config, err = defaultTaskToolConfig(ctx) if err != nil { return nil, err } } if config.Storage == nil { return nil, fmt.Errorf("storage cannot be empty") } t := &TaskToolImpl{config: config} tn, err = t.ToEinoTool() if err != nil { return nil, err } return tn, nil } func (t *TaskToolImpl) ToEinoTool() (tool.BaseTool, error) { return utils.InferTool("task_manager", "task manager tool, you can add, get, update, delete, list tasks", t.Invoke) } func (t *TaskToolImpl) Invoke(ctx context.Context, req *TaskRequest) (res *TaskResponse, err error) { res = &TaskResponse{} switch req.Action { case ActionAdd: if req.Task == nil { res.Status = "error" res.Error = "task is required for add action" return res, nil } if req.Task.Title == "" { res.Status = "error" res.Error = "title is required" return res, nil } req.Task.ID = uuid.New().String() if err := t.config.Storage.Add(req.Task); err != nil { res.Status = "error" res.Error = fmt.Sprintf("failed to add task: %v", err) return res, nil } res.TaskList = []*Task{req.Task} case ActionUpdate: if req.Task == nil { res.Status = "error" res.Error = "task is required for update action" return res, nil } if req.Task.ID == "" { res.Status = "error" res.Error = "id is required" return res, nil } if err := t.config.Storage.Update(req.Task); err != nil { res.Status = "error" res.Error = fmt.Sprintf("failed to update task: %v", err) return res, nil } res.TaskList = []*Task{req.Task} case ActionDelete: if req.Task == nil || req.Task.ID == "" { res.Status = "error" res.Error = "task id is required for delete action" return res, nil } if err := t.config.Storage.Delete(req.Task.ID); err != nil { res.Status = "error" res.Error = fmt.Sprintf("failed to delete task: %v", err) return res, nil } case ActionList: if req.List == nil { req.List = &ListParams{} } tasks, err := t.config.Storage.List(req.List) if err != nil { res.Status = "error" res.Error = fmt.Sprintf("failed to list tasks: %v", err) return res, nil } res.TaskList = tasks default: res.Status = "error" res.Error = fmt.Sprintf("unknown action: %s", req.Action) } res.Status = "success" return res, nil }