Skip to content
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,9 @@ memory:
max_prompt_chars: 1800
max_items: 1000
storage_path: "./data/memory_rules.json"
extractor: "rule"
extractor_model: ""
extractor_timeout_seconds: 20
persist_types:
- "user_preference"
- "project_rule"
Expand Down
57 changes: 48 additions & 9 deletions cmd/server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@ package main
import (
"fmt"
"path/filepath"
"strings"
"time"

"go-llm-demo/configs"
"go-llm-demo/internal/server/domain"
"go-llm-demo/internal/server/infra/provider"
"go-llm-demo/internal/server/infra/repository"
"go-llm-demo/internal/server/infra/tools"
Expand All @@ -14,37 +17,45 @@ import (
func main() {
workspaceRoot, err := tools.ResolveWorkspaceRoot("")
if err != nil {
fmt.Printf("解析工作区失败:%v\n", err)
fmt.Printf("failed to resolve workspace: %v\n", err)
return
}
if err := tools.SetWorkspaceRoot(workspaceRoot); err != nil {
fmt.Printf("设置工作区失败:%v\n", err)
fmt.Printf("failed to set workspace: %v\n", err)
return
}
if err := initializeSecurity(filepath.Join(workspaceRoot, "configs", "security")); err != nil {
fmt.Printf("初始化安全策略失败:%v\n", err)
fmt.Printf("failed to initialize security: %v\n", err)
return
}

if err := configs.LoadAppConfig("config.yaml"); err != nil {
fmt.Printf("加载配置失败:%v\n", err)
fmt.Printf("failed to load config: %v\n", err)
return
}

cfg := configs.GlobalAppConfig
memoryRepo := repository.NewFileMemoryStore(cfg.Memory.StoragePath, cfg.Memory.MaxItems)
sessionRepo := repository.NewSessionMemoryStore(cfg.Memory.MaxItems)
workingRepo := repository.NewWorkingMemoryStore()
memorySvc := service.NewMemoryService(

memoryExtractor, err := buildMemoryExtractor(cfg)
if err != nil {
fmt.Printf("failed to initialize memory extractor: %v\n", err)
return
}
memorySvc := service.NewMemoryServiceWithExtractor(
memoryRepo,
sessionRepo,
memoryExtractor,
cfg.Memory.TopK,
cfg.Memory.MinMatchScore,
cfg.Memory.MaxPromptChars,
cfg.Memory.StoragePath,
cfg.Memory.PersistTypes,
)
workingSvc := service.NewWorkingMemoryService(workingRepo, cfg.History.ShortTermTurns, tools.GetWorkspaceRoot())
projectMemorySvc := service.NewProjectMemoryService(tools.GetWorkspaceRoot(), cfg.Memory.ProjectFiles, cfg.Memory.ProjectPromptChars)

roleRepo := repository.NewFileRoleStore("./data/roles.json")
roleSvc := service.NewRoleService(roleRepo, cfg.Persona.FilePath)
Expand All @@ -54,13 +65,41 @@ func main() {

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

chatGateway := service.NewChatService(memorySvc, workingSvc, todoSvc, roleSvc, chatProvider)
fmt.Printf("服务器已初始化并加载服务: %+v\n", chatGateway)
fmt.Println("注意:这是一个占位符。实际的服务器实现将在此处进行.")
chatGateway := service.NewChatService(memorySvc, workingSvc, projectMemorySvc, todoSvc, roleSvc, chatProvider)
fmt.Printf("server dependencies initialized: %+v\n", chatGateway)
fmt.Println("note: cmd/server is still a wiring check entrypoint, not a production server.")
}

func buildMemoryExtractor(cfg *configs.AppConfiguration) (domain.MemoryExtractor, error) {
if cfg == nil {
return service.BuildMemoryExtractor(service.MemoryExtractorModeRule, nil, service.LLMMemoryExtractorOptions{})
}

mode := strings.TrimSpace(cfg.Memory.Extractor)
if mode == "" || strings.EqualFold(mode, service.MemoryExtractorModeRule) {
return service.BuildMemoryExtractor(service.MemoryExtractorModeRule, nil, service.LLMMemoryExtractorOptions{})
}

model := strings.TrimSpace(cfg.Memory.ExtractorModel)
if model == "" {
model = strings.TrimSpace(cfg.AI.Model)
}

extractorProvider, err := provider.NewChatProvider(model)
if err != nil {
if strings.EqualFold(mode, service.MemoryExtractorModeAuto) {
return service.BuildMemoryExtractor(service.MemoryExtractorModeAuto, nil, service.LLMMemoryExtractorOptions{})
}
return nil, err
}

return service.BuildMemoryExtractor(mode, extractorProvider, service.LLMMemoryExtractorOptions{
Timeout: time.Duration(cfg.Memory.ExtractorTimeoutSecond) * time.Second,
})
}

func initializeSecurity(configDir string) error {
Expand Down
17 changes: 15 additions & 2 deletions config.example.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# 应用配置文件示例
# Example application configuration
app:
name: "NeoCode"
version: "1.0.0"

ai:
provider: "openll" # modelscope | deepseek | openll | siliconflow | 豆包大模型 | openai
provider: "openll" # modelscope | deepseek | openll | siliconflow | doubao | openai
api_key: "AI_API_KEY" # environment variable name; falls back to AI_API_KEY when empty
model: "gpt-5.4"

Expand All @@ -14,6 +14,19 @@ memory:
max_prompt_chars: 1800
max_items: 1000
storage_path: "./data/memory_rules.json"
# 显式项目记忆文件。默认兼容业界通用的 AGENTS.md。
# 如需兼容仓库里已有的其他约定文件,可继续追加到列表末尾;
# 系统按列表顺序加载,越靠前优先级越高。
project_files:
- "AGENTS.md" # 首选项目级约定文件;建议把仓库协作规则集中维护在这里。
# 显式项目记忆注入到 prompt 时的最大字符数预算。
project_prompt_chars: 2400
# 记忆提取策略:rule | llm | auto。
extractor: "rule"
# 仅在 llm/auto 模式下使用;为空时默认复用 ai.model。
extractor_model: ""
# 单次 LLM 记忆提取请求的超时时间(秒),用于限制额外提取链路的等待时间。
extractor_timeout_seconds: 20
Comment thread
wynxing marked this conversation as resolved.
persist_types:
- "user_preference"
- "project_rule"
Expand Down
Loading