feat: implement streaming chat, skill routing, and SAFe PI planning tools
- Add /api/chat/stream endpoint with Server-Sent Events (SSE) for real-time message streaming * Implement StreamEvent types (thought, tool_call, tool_result, final, error) * Add StreamEventCallback mechanism for event propagation * Create StreamChatHandler in webui/bot with proper HTTP headers and flushing - Implement LLM-based skill router for intelligent capability selection * Add optional routerLLM client for semantic routing * Implement routeSkillsWithLLM() to match user intent to available skills * Add matchSkillsByName() for fuzzy skill matching * Update buildUnifiedSystemPrompt() to use routed skills - Add streaming support to ReAct pipeline * Implement runUnifiedReActStream() for streaming thought/action/observation * Emit StreamEvent at each ReAct step * Support callback error handling in streaming mode - Integrate three new DevOps tools * tools/filedoc: Extract document content from file_id via OpenAI * tools/giteaticket: Create Gitea issues from PI plan items with SAFe metadata * tools/piplan: Publish PI planning blueprints with dependency tracking - Add SAFe PI Planning skill * Implement PM/SA/RTE (iron triangle) workflow * Support for Feature, Enabler, and Dependency definition * Automatic task decomposition and Gitea integration - Create frontend integration documentation * Complete SSE protocol specification * TypeScript fetch + ReadableStream example * LLM-ready refactoring template for other projects - Simplify file handling * Remove legacy file context structures and dual-mode processing * Consolidate file operations into UploadAndCacheFiles() * Remove FilePromptMode configuration and related complexity - Update configuration * Add Router model support (LLM_ROUTER_MODEL) * Add Gitea configuration (BaseURL, Token, Owner, Repo) * WebSearch and additional tool infrastructure Tests: All 22 test packages passing, 8/8 webui tests including 3 new stream tests
This commit is contained in:
@@ -126,9 +126,19 @@ func main() {
|
||||
// 实例化 LLM 客户端
|
||||
llmClient := llm.NewOpenAICompatibleClient(cfg.LLM, appLogger.WithComponent("llm"))
|
||||
|
||||
// 实例化路由 LLM 客户端(如果配置了独立的路由模型)
|
||||
var routerLLMClient llm.Client
|
||||
if cfg.LLM.RouterModel != "" {
|
||||
routerCfg := cfg.LLM
|
||||
routerCfg.Model = cfg.LLM.RouterModel
|
||||
routerLLMClient = llm.NewOpenAICompatibleClient(routerCfg, appLogger.WithComponent("llm.router"))
|
||||
appLogger.Infof("skill router enabled, model=%s", cfg.LLM.RouterModel)
|
||||
}
|
||||
|
||||
// 创建编排器,整合 LLM、记忆系统、知识技能库与各种工具
|
||||
engine := agent.NewOrchestrator(
|
||||
llmClient,
|
||||
routerLLMClient,
|
||||
store,
|
||||
toolRegistry,
|
||||
soul,
|
||||
@@ -207,11 +217,18 @@ func runMessageChannel(ctx context.Context, cfg config.Config, engine *agent.Orc
|
||||
return wb.Run(
|
||||
ctx,
|
||||
func(ctx context.Context, msg webui.IncomingMessage) (string, error) {
|
||||
if len(msg.FileIDs) > 0 {
|
||||
return engine.HandleMessageWithFileIDs(ctx, msg.ChatID, msg.UserID, msg.Text, msg.FileIDs)
|
||||
}
|
||||
return engine.HandleMessage(ctx, msg.ChatID, msg.UserID, msg.Text)
|
||||
},
|
||||
func(ctx context.Context, msg webui.IncomingMessage, callback webui.StreamEventCallback) (string, error) {
|
||||
return engine.HandleMessageStream(ctx, msg.ChatID, msg.UserID, msg.Text, func(event agent.StreamEvent) error {
|
||||
return callback(webui.StreamEvent{
|
||||
Type: webui.StreamEventType(event.Type),
|
||||
Content: event.Content,
|
||||
Step: event.Step,
|
||||
ToolName: event.ToolName,
|
||||
})
|
||||
})
|
||||
},
|
||||
func(ctx context.Context, chatID, userID string, files []llm.InputFile) ([]string, error) {
|
||||
return engine.UploadAndCacheFiles(ctx, chatID, userID, files)
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user