diff options
| author | Grail Finder <wohilas@gmail.com> | 2025-12-08 16:19:06 +0300 |
|---|---|---|
| committer | Grail Finder <wohilas@gmail.com> | 2025-12-08 16:19:06 +0300 |
| commit | dc71009f43a2294aafab2a7fcd7d67d71c70c562 (patch) | |
| tree | 1e5e35f4951885f6d6152f66a81b2d85a6e66cda | |
| parent | 923ce0c23c9fce569e38e3928e75c80dc373c499 (diff) | |
Feat: todo tools
| -rw-r--r-- | tools.go | 303 |
1 files changed, 303 insertions, 0 deletions
@@ -543,6 +543,225 @@ func executeCommand(args map[string]string) []byte { // Helper functions for command execution +// Todo structure +type TodoItem struct { + ID string `json:"id"` + Task string `json:"task"` + Status string `json:"status"` // "pending", "in_progress", "completed" +} + +type TodoList struct { + Items []TodoItem `json:"items"` +} + +// Global todo list storage +var globalTodoList = TodoList{ + Items: []TodoItem{}, +} + +func getTodoList() TodoList { + return globalTodoList +} + +func setTodoList(todoList TodoList) { + globalTodoList = todoList +} + +// Todo Management Tools +func todoCreate(args map[string]string) []byte { + task, ok := args["task"] + if !ok || task == "" { + msg := "task not provided to todo_create tool" + logger.Error(msg) + return []byte(msg) + } + + // Generate simple ID + id := fmt.Sprintf("todo_%d", len(globalTodoList.Items)+1) + + newItem := TodoItem{ + ID: id, + Task: task, + Status: "pending", + } + + globalTodoList.Items = append(globalTodoList.Items, newItem) + + result := map[string]string{ + "message": "todo created successfully", + "id": id, + "task": task, + "status": "pending", + } + + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult +} + +func todoRead(args map[string]string) []byte { + id, ok := args["id"] + if ok && id != "" { + // Find specific todo by ID + for _, item := range globalTodoList.Items { + if item.ID == id { + result := map[string]interface{}{ + "todo": item, + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + return jsonResult + } + } + // ID not found + result := map[string]string{ + "error": fmt.Sprintf("todo with id %s not found", id), + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + return jsonResult + } + + // Return all todos if no ID specified + result := map[string]interface{}{ + "todos": globalTodoList.Items, + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult +} + +func todoUpdate(args map[string]string) []byte { + id, ok := args["id"] + if !ok || id == "" { + msg := "id not provided to todo_update tool" + logger.Error(msg) + return []byte(msg) + } + + task, taskOk := args["task"] + status, statusOk := args["status"] + + if !taskOk && !statusOk { + msg := "neither task nor status provided to todo_update tool" + logger.Error(msg) + return []byte(msg) + } + + // Find and update the todo + for i, item := range globalTodoList.Items { + if item.ID == id { + if taskOk { + globalTodoList.Items[i].Task = task + } + if statusOk { + // Validate status + if status == "pending" || status == "in_progress" || status == "completed" { + globalTodoList.Items[i].Status = status + } else { + result := map[string]string{ + "error": "status must be one of: pending, in_progress, completed", + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + return jsonResult + } + } + + result := map[string]string{ + "message": "todo updated successfully", + "id": id, + } + + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult + } + } + + // ID not found + result := map[string]string{ + "error": fmt.Sprintf("todo with id %s not found", id), + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + return jsonResult +} + +func todoDelete(args map[string]string) []byte { + id, ok := args["id"] + if !ok || id == "" { + msg := "id not provided to todo_delete tool" + logger.Error(msg) + return []byte(msg) + } + + // Find and remove the todo + for i, item := range globalTodoList.Items { + if item.ID == id { + // Remove item from slice + globalTodoList.Items = append(globalTodoList.Items[:i], globalTodoList.Items[i+1:]...) + + result := map[string]string{ + "message": "todo deleted successfully", + "id": id, + } + + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + + return jsonResult + } + } + + // ID not found + result := map[string]string{ + "error": fmt.Sprintf("todo with id %s not found", id), + } + jsonResult, err := json.Marshal(result) + if err != nil { + msg := "failed to marshal result; error: " + err.Error() + logger.Error(msg) + return []byte(msg) + } + return jsonResult +} + func isCommandAllowed(command string) bool { allowedCommands := map[string]bool{ "grep": true, @@ -584,6 +803,10 @@ var fnMap = map[string]fnSig{ "file_copy": fileCopy, "file_list": fileList, "execute_command": executeCommand, + "todo_create": todoCreate, + "todo_read": todoRead, + "todo_update": todoUpdate, + "todo_delete": todoDelete, } // openai style def @@ -839,4 +1062,84 @@ var baseTools = []models.Tool{ }, }, }, + // todo_create + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "todo_create", + Description: "Create a new todo item with a task. Returns the created todo with its ID.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"task"}, + Properties: map[string]models.ToolArgProps{ + "task": models.ToolArgProps{ + Type: "string", + Description: "the task description to add to the todo list", + }, + }, + }, + }, + }, + // todo_read + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "todo_read", + Description: "Read todo items. Without ID returns all todos, with ID returns specific todo.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{}, + Properties: map[string]models.ToolArgProps{ + "id": models.ToolArgProps{ + Type: "string", + Description: "optional id of the specific todo item to read", + }, + }, + }, + }, + }, + // todo_update + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "todo_update", + Description: "Update a todo item by ID with new task or status. Status must be one of: pending, in_progress, completed.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"id"}, + Properties: map[string]models.ToolArgProps{ + "id": models.ToolArgProps{ + Type: "string", + Description: "id of the todo item to update", + }, + "task": models.ToolArgProps{ + Type: "string", + Description: "new task description (optional)", + }, + "status": models.ToolArgProps{ + Type: "string", + Description: "new status for the todo: pending, in_progress, or completed (optional)", + }, + }, + }, + }, + }, + // todo_delete + models.Tool{ + Type: "function", + Function: models.ToolFunc{ + Name: "todo_delete", + Description: "Delete a todo item by ID. Returns success message.", + Parameters: models.ToolFuncParams{ + Type: "object", + Required: []string{"id"}, + Properties: map[string]models.ToolArgProps{ + "id": models.ToolArgProps{ + Type: "string", + Description: "id of the todo item to delete", + }, + }, + }, + }, + }, } |
