Add streaming support and refactor Chat UI

- Add run_stream method to AgentCore for streaming output
- Add base_url parameter to LLM clients for OpenRouter support
- Add xbot module for new agent implementation
- Refactor Chat.vue into composable + components (ChatHeader, ChatMessage, ChatInput, ChatSidebar, ChatAgentSelector)
- Add ChatStream handler for SSE streaming in Go server
- Add UseXBot field to chat request

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-12 10:49:44 +08:00
parent 8062144001
commit 5c435ab21e
31 changed files with 2762 additions and 760 deletions

View File

@@ -41,66 +41,75 @@ func (s *SkillService) UpdateSkill(skill *model.Skill) error {
}
func (s *SkillService) DeleteSkill(id string) error {
return s.skillRepo.Delete(id)
// 先获取 skill 信息,以便删除本地文件
skill, err := s.skillRepo.FindByID(id)
if err != nil {
return err
}
// 删除数据库记录
if err := s.skillRepo.Delete(id); err != nil {
return err
}
// 删除本地文件skill 目录)
if skill.Path != "" {
// 获取 skill 所在目录SKILL.md 的父目录)
skillDir := filepath.Dir(skill.Path)
if err := os.RemoveAll(skillDir); err != nil {
log.Printf("[SkillService] Warning: failed to delete skill directory %s: %v", skillDir, err)
// 数据库记录已删除,不返回错误
} else {
log.Printf("[SkillService] Deleted skill directory: %s", skillDir)
}
}
return nil
}
// InitSkills 初始化扫描所有 skills 目录
func (s *SkillService) InitSkills() error {
log.Println("[SkillService] Starting init skills...")
// 获取项目根目录
projectRoot := s.getProjectRoot()
if projectRoot == "" {
log.Println("[SkillService] Cannot determine project root, skipping skill init")
return nil
}
var totalCount int
// 扫描 system skills: account/admin/skills
systemSkillsPath := filepath.Join(projectRoot, "account", "admin", "skills")
if _, err := os.Stat(systemSkillsPath); err == nil {
log.Printf("[SkillService] Scanning system skills from: %s", systemSkillsPath)
systemSkills, err := s.scanSkillsDirectory(systemSkillsPath, "system")
if err != nil {
log.Printf("[SkillService] Error scanning system skills: %v", err)
} else {
log.Printf("[SkillService] Found %d system skills", len(systemSkills))
// 先删除旧的 system skills
if err == nil && len(systemSkills) > 0 {
s.skillRepo.DeleteByType("system")
// 批量插入
if err := s.skillRepo.UpsertBatch(systemSkills); err != nil {
log.Printf("[SkillService] Error saving system skills: %v", err)
}
s.skillRepo.UpsertBatch(systemSkills)
totalCount += len(systemSkills)
}
}
// 扫描 user skills: account/{username}/skills (除了 admin)
accountPath := filepath.Join(projectRoot, "account")
entries, err := os.ReadDir(accountPath)
if err != nil {
log.Printf("[SkillService] Error reading account directory: %v", err)
} else {
if err == nil {
for _, entry := range entries {
if !entry.IsDir() || entry.Name() == "admin" {
continue
}
userSkillsPath := filepath.Join(accountPath, entry.Name(), "skills")
if _, err := os.Stat(userSkillsPath); err == nil {
log.Printf("[SkillService] Scanning user skills for %s from: %s", entry.Name(), userSkillsPath)
userSkills, err := s.scanSkillsDirectory(userSkillsPath, "user")
if err != nil {
log.Printf("[SkillService] Error scanning user skills for %s: %v", entry.Name(), err)
} else {
log.Printf("[SkillService] Found %d user skills for %s", len(userSkills), entry.Name())
// 批量插入
if err := s.skillRepo.UpsertBatch(userSkills); err != nil {
log.Printf("[SkillService] Error saving user skills for %s: %v", entry.Name(), err)
}
if err == nil && len(userSkills) > 0 {
s.skillRepo.UpsertBatch(userSkills)
totalCount += len(userSkills)
}
}
}
}
log.Println("[SkillService] Skills initialized successfully")
if totalCount > 0 {
log.Printf("[SkillService] Loaded %d skills", totalCount)
}
return nil
}