Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,18 @@ func main() {
roleRepo := repository.NewFileRoleStore("./data/roles.json")
roleSvc := service.NewRoleService(roleRepo, cfg.Persona.FilePath)

todoRepo := repository.NewInMemoryTodoRepository()
todoSvc := service.NewTodoService(todoRepo)

chatProvider, err := provider.NewChatProvider(cfg.AI.Model)
if err != nil {
fmt.Printf("初始化 ChatProvider 失败:%v\n", err)
return
}

chatGateway := service.NewChatService(memorySvc, workingSvc, roleSvc, chatProvider)
fmt.Printf("Server initialized with services: %+v\n", chatGateway)
fmt.Println("Note: This is a placeholder. Actual server implementation goes here.")
chatGateway := service.NewChatService(memorySvc, workingSvc, todoSvc, roleSvc, chatProvider)
fmt.Printf("服务器已初始化并加载服务: %+v\n", chatGateway)
fmt.Println("注意:这是一个占位符。实际的服务器实现将在此处进行.")
}

func initializeSecurity(configDir string) error {
Expand Down
36 changes: 23 additions & 13 deletions configs/app_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ type AppConfiguration struct {
} `yaml:"memory"`

History struct {
ShortTermTurns int `yaml:"short_term_turns"`
ShortTermTurns int `yaml:"short_term_turns"`
MaxToolContextMessages int `yaml:"max_tool_context_messages"`
MaxToolContextOutputSize int `yaml:"max_tool_context_output_size"`
} `yaml:"history"`

Persona struct {
Expand All @@ -58,6 +60,8 @@ func DefaultAppConfig() *AppConfiguration {
cfg.Memory.StoragePath = "./data/memory_rules.json"
cfg.Memory.PersistTypes = []string{"user_preference", "project_rule", "code_fact", "fix_recipe"}
cfg.History.ShortTermTurns = 6
cfg.History.MaxToolContextMessages = 3
cfg.History.MaxToolContextOutputSize = 4000
cfg.Persona.FilePath = DefaultPersonaFilePath
return cfg
}
Expand Down Expand Up @@ -112,7 +116,7 @@ func EnsureConfigFile(filePath string) (*AppConfiguration, bool, error) {
// WriteAppConfig 将应用配置写入磁盘。
func WriteAppConfig(filePath string, cfg *AppConfiguration) error {
if cfg == nil {
return fmt.Errorf("配置信息为空")
return fmt.Errorf("应用配置不能为空")
}
cfgCopy := *cfg
cfgCopy.AI.APIKey = strings.TrimSpace(cfgCopy.AI.APIKey)
Expand All @@ -134,36 +138,42 @@ func (c *AppConfiguration) Validate() error {
// ValidateBase 检查不包含密钥的基础配置是否合法。
func (c *AppConfiguration) ValidateBase() error {
if c == nil {
return fmt.Errorf("app config is nil")
return fmt.Errorf("应用配置不能为空")
}
providerName := normalizeProviderName(c.AI.Provider)
if providerName == "" {
return fmt.Errorf("invalid config: ai.provider is required")
return fmt.Errorf("配置无效:需要 ai.provider")
}
if !isSupportedProvider(providerName) {
return fmt.Errorf("invalid config: unsupported ai.provider %q", strings.TrimSpace(c.AI.Provider))
return fmt.Errorf("配置无效:不支持的 ai.provider %q", strings.TrimSpace(c.AI.Provider))
}
c.AI.Provider = providerName
if strings.TrimSpace(c.AI.Model) == "" {
return fmt.Errorf("invalid config: ai.model is required")
return fmt.Errorf("配置无效:需要 ai.model")
}
if c.Memory.TopK <= 0 {
return fmt.Errorf("invalid config: memory.top_k must be greater than 0")
return fmt.Errorf("配置无效:memory.top_k 必须大于 0")
}
if c.Memory.MinMatchScore < 0 {
return fmt.Errorf("invalid config: memory.min_match_score must not be negative")
return fmt.Errorf("配置无效:memory.min_match_score 不能为负数")
}
if c.Memory.MaxPromptChars <= 0 {
return fmt.Errorf("invalid config: memory.max_prompt_chars must be greater than 0")
return fmt.Errorf("配置无效:memory.max_prompt_chars 必须大于 0")
}
if c.Memory.MaxItems <= 0 {
return fmt.Errorf("invalid config: memory.max_items must be greater than 0")
return fmt.Errorf("配置无效:memory.max_items 必须大于 0")
}
if strings.TrimSpace(c.Memory.StoragePath) == "" {
return fmt.Errorf("invalid config: memory.storage_path is required")
return fmt.Errorf("配置无效:需要 memory.storage_path")
}
if c.History.ShortTermTurns <= 0 {
return fmt.Errorf("invalid config: history.short_term_turns must be greater than 0")
return fmt.Errorf("配置无效:history.short_term_turns 必须大于 0")
}
if c.History.MaxToolContextMessages < 0 {
return fmt.Errorf("配置无效:history.max_tool_context_messages 不能为负数")
}
if c.History.MaxToolContextOutputSize <= 0 {
return fmt.Errorf("配置无效:history.max_tool_context_output_size 必须大于 0")
}
return nil
}
Expand All @@ -175,7 +185,7 @@ func (c *AppConfiguration) ValidateRuntime() error {
}
envVarName := c.APIKeyEnvVarName()
if c.RuntimeAPIKey() == "" {
return fmt.Errorf("invalid runtime: %s environment variable is required", envVarName)
return fmt.Errorf("运行时无效:需要 %s 环境变量", envVarName)
}
return nil
}
Expand Down
4 changes: 3 additions & 1 deletion configs/app_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func TestAppConfigurationValidateBaseRejectsUnsupportedProvider(t *testing.T) {
cfg.AI.Provider = "unknown"

err := cfg.ValidateBase()
if err == nil || !strings.Contains(err.Error(), "unsupported ai.provider") {
if err == nil || !strings.Contains(err.Error(), "不支持的 ai.provider") {
t.Fatalf("expected unsupported provider error, got: %v", err)
}
}
Expand Down Expand Up @@ -191,6 +191,8 @@ func validConfig() *AppConfiguration {
cfg.Memory.StoragePath = "./data/memory_rules.json"
cfg.Memory.PersistTypes = []string{"user_preference", "project_rule", "code_fact", "fix_recipe"}
cfg.History.ShortTermTurns = 6
cfg.History.MaxToolContextMessages = 3
cfg.History.MaxToolContextOutputSize = 4000
cfg.Persona.FilePath = DefaultPersonaFilePath
return cfg
}
Expand Down
9 changes: 9 additions & 0 deletions configs/persona.txt

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里看上去写的更像是markdown?而不是 txt ?

Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@
- 涉及路径操作时,默认限定在当前工作区内,不对工作区外路径进行读写。

你可以调用edit,grep,list,read,write,bash工具,规范和opencode保持一致
你可以调用edit,grep,list,read,write,“todo”工具,规范和opencode保持一致

Comment thread
phantom5099 marked this conversation as resolved.
当需要管理任务清单以追踪复杂任务进度时,调用 todo 工具。
操作类型(action):
- add: 添加新任务。参数:content(任务内容), priority(优先级:high/medium/low)
- update: 更新任务状态。参数:id(任务ID,如todo-1), status(pending/in_progress/completed)
- list: 列出所有任务。
- remove: 移除特定任务。参数:id
- clear: 清空所有任务。

当需要查看指定目录下的文件 / 目录结构时,调用 list 工具。
必填参数:path(目标目录路径,如/home/project);
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@ module go-llm-demo
go 1.26.1

require (
github.com/bmatcuk/doublestar/v4 v4.10.0
github.com/charmbracelet/bubbles v1.0.0
github.com/charmbracelet/bubbletea v1.3.10
github.com/charmbracelet/lipgloss v1.1.0
golang.org/x/sys v0.38.0
google.golang.org/protobuf v1.36.11
gopkg.in/yaml.v3 v3.0.1
)

require (
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
github.com/charmbracelet/bubbles v1.0.0 // indirect
github.com/charmbracelet/colorprofile v0.4.1 // indirect
github.com/charmbracelet/x/ansi v0.11.6 // indirect
github.com/charmbracelet/x/cellbuf v0.0.15 // indirect
Expand All @@ -29,8 +32,5 @@ require (
github.com/muesli/termenv v0.16.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.3.8 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
26 changes: 8 additions & 18 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,50 +1,43 @@
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/aymanbagabas/go-udiff v0.3.1 h1:LV+qyBQ2pqe0u42ZsUEtPiCaUoqgA9gYRDs3vj1nolY=
github.com/aymanbagabas/go-udiff v0.3.1/go.mod h1:G0fsKmG+P6ylD0r6N/KgQD/nWzgfnl8ZBcNLgcbrw8E=
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/charmbracelet/bubbles v1.0.0 h1:12J8/ak/uCZEMQ6KU7pcfwceyjLlWsDLAxB5fXonfvc=
github.com/charmbracelet/bubbles v1.0.0/go.mod h1:9d/Zd5GdnauMI5ivUIVisuEm3ave1XwXtD1ckyV6r3E=
github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw=
github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
github.com/charmbracelet/colorprofile v0.4.1 h1:a1lO03qTrSIRaK8c3JRxJDZOvhvIeSco3ej+ngLk1kk=
github.com/charmbracelet/colorprofile v0.4.1/go.mod h1:U1d9Dljmdf9DLegaJ0nGZNJvoXAhayhmidOdcBwAvKk=
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
github.com/charmbracelet/x/ansi v0.10.1 h1:rL3Koar5XvX0pHGfovN03f5cxLbCF2YvLeyz7D2jVDQ=
github.com/charmbracelet/x/ansi v0.10.1/go.mod h1:3RQDQ6lDnROptfpWuUVIUG64bD2g2BgntdxH0Ya5TeE=
github.com/charmbracelet/x/ansi v0.11.6 h1:GhV21SiDz/45W9AnV2R61xZMRri5NlLnl6CVF7ihZW8=
github.com/charmbracelet/x/ansi v0.11.6/go.mod h1:2JNYLgQUsyqaiLovhU2Rv/pb8r6ydXKS3NIttu3VGZQ=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8=
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
github.com/charmbracelet/x/cellbuf v0.0.15 h1:ur3pZy0o6z/R7EylET877CBxaiE1Sp1GMxoFPAIztPI=
github.com/charmbracelet/x/cellbuf v0.0.15/go.mod h1:J1YVbR7MUuEGIFPCaaZ96KDl5NoS0DAWkskup+mOY+Q=
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
github.com/charmbracelet/x/term v0.2.2 h1:xVRT/S2ZcKdhhOuSP4t5cLi5o+JxklsoEObBSgfgZRk=
github.com/charmbracelet/x/term v0.2.2/go.mod h1:kF8CY5RddLWrsgVwpw4kAa6TESp6EB5y3uxGLeCqzAI=
github.com/clipperhouse/displaywidth v0.9.0 h1:Qb4KOhYwRiN3viMv1v/3cTBlz3AcAZX3+y9OLhMtAtA=
github.com/clipperhouse/displaywidth v0.9.0/go.mod h1:aCAAqTlh4GIVkhQnJpbL0T/WfcrJXHcj8C0yjYcjOZA=
github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs=
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
github.com/clipperhouse/uax29/v2 v2.2.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
github.com/clipperhouse/uax29/v2 v2.5.0 h1:x7T0T4eTHDONxFJsL94uKNKPHrclyFI0lm7+w94cO8U=
github.com/clipperhouse/uax29/v2 v2.5.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4=
github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag=
github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4=
github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw=
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI=
Expand All @@ -53,24 +46,21 @@ github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELU
github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo=
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
94 changes: 94 additions & 0 deletions internal/server/domain/todo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package domain

import (
"context"
"strings"
)

// TodoStatus 表示任务状态
type TodoStatus string

const (
TodoPending TodoStatus = "pending"
TodoInProgress TodoStatus = "in_progress"
TodoCompleted TodoStatus = "completed"
)

func ParseTodoStatus(input string) (TodoStatus, bool) {
normalized := TodoStatus(strings.ToLower(strings.TrimSpace(input)))
switch normalized {
case TodoPending, TodoInProgress, TodoCompleted:
return normalized, true
default:
return "", false
}
}

type TodoPriority string

const (
TodoPriorityHigh TodoPriority = "high"
TodoPriorityMedium TodoPriority = "medium"
TodoPriorityLow TodoPriority = "low"
)

func ParseTodoPriority(input string) (TodoPriority, bool) {
normalized := TodoPriority(strings.ToLower(strings.TrimSpace(input)))
switch normalized {
case TodoPriorityHigh, TodoPriorityMedium, TodoPriorityLow:
return normalized, true
default:
return "", false
}
}

type TodoAction string

const (
TodoActionAdd TodoAction = "add"
TodoActionUpdate TodoAction = "update"
TodoActionList TodoAction = "list"
TodoActionRemove TodoAction = "remove"
TodoActionClear TodoAction = "clear"
)

func ParseTodoAction(input string) (TodoAction, bool) {
normalized := TodoAction(strings.ToLower(strings.TrimSpace(input)))
switch normalized {
case TodoActionAdd, TodoActionUpdate, TodoActionList, TodoActionRemove, TodoActionClear:
return normalized, true
default:
return "", false
}
}

// Todo 表示任务清单中的一项
type Todo struct {
ID string `json:"id"`
Content string `json:"content"`
Status TodoStatus `json:"status"`
Priority TodoPriority `json:"priority"`
}
Comment thread
phantom5099 marked this conversation as resolved.

// TodoService 定义任务清单服务接口
type TodoService interface {
// AddTodo 添加一个新任务
AddTodo(ctx context.Context, content string, priority TodoPriority) (*Todo, error)
// UpdateTodoStatus 更新任务状态
UpdateTodoStatus(ctx context.Context, id string, status TodoStatus) error
// ListTodos 获取所有任务
ListTodos(ctx context.Context) ([]Todo, error)
// ClearTodos 清空所有任务
ClearTodos(ctx context.Context) error
// RemoveTodo 移除特定任务
RemoveTodo(ctx context.Context, id string) error
}

// TodoRepository 定义任务清单存储接口
type TodoRepository interface {
Add(ctx context.Context, todo Todo) (*Todo, error)
UpdateStatus(ctx context.Context, id string, status TodoStatus) error
List(ctx context.Context) ([]Todo, error)
Clear(ctx context.Context) error
Remove(ctx context.Context, id string) error
}
Loading