feat: Agent CLI 与终端审计回放全面优化
- Agent CLI: 多轮对话、SSH 长连接、流式推理、Evolver 按用户隔离、历史侧栏 - 终端审计: 回放播放器、命令书签、筛选分页导出、命令输出统计、录制落盘修复 - 修复 session_commands 表迁移、Kill 竞态导致录制丢失、无录制会话回放提示 - 审计历史页只读(移除删除),移除回放弹框录制搜索
This commit is contained in:
1 parent
9a3dd304f7
commit
1acb0c49af
81 files changed
+3916
-1655
No files matched your search
@@ -14,18 +14,6 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// buildLLMClient 从数据库配置构造 LLM 客户端(按 provider 协议自动路由 OpenAI/Anthropic) // Logan.Li
|
||||
func (h *LLMHandler) buildLLMClient(cfg model.LLMConfig) llm.Client {
|
||||
return llm.NewClient(llm.Config{
|
||||
Protocol: resolveProtocol(cfg.Provider),
|
||||
Endpoint: resolveEndpoint(cfg.Provider, cfg.Endpoint),
|
||||
APIKey: cfg.APIKey,
|
||||
Model: cfg.Model,
|
||||
Temperature: cfg.Temperature,
|
||||
MaxTokens: cfg.MaxTokens,
|
||||
})
|
||||
}
|
||||
|
||||
// toLLMMessages model.ChatMessage[] → llm.Message[](智能助手纯对话,仅填 Role/Content) // Logan.Li
|
||||
func toLLMMessages(msgs []model.ChatMessage) []llm.Message {
|
||||
out := make([]llm.Message, len(msgs))
|
||||
@@ -57,7 +45,7 @@ func (h *LLMHandler) Chat(c *gin.Context) {
|
||||
}
|
||||
messages := append([]model.ChatMessage{{Role: "system", Content: systemPrompt}}, req.Messages...)
|
||||
|
||||
resp, err := h.buildLLMClient(cfg).Complete(c.Request.Context(), &llm.CompletionRequest{
|
||||
resp, err := buildLLMClientFromConfig(cfg).Complete(c.Request.Context(), &llm.CompletionRequest{
|
||||
Messages: toLLMMessages(messages),
|
||||
})
|
||||
if err != nil {
|
||||
@@ -127,7 +115,7 @@ func (h *LLMHandler) ChatStream(c *gin.Context) {
|
||||
|
||||
// 流式补全:逐 token 回调转发 SSE;ctx 取消(客户端断开)由 llm.Client 内部终止上游读取
|
||||
var contentBuilder strings.Builder
|
||||
_, streamErr := h.buildLLMClient(cfg).Stream(c.Request.Context(), &llm.CompletionRequest{
|
||||
_, streamErr := buildLLMClientFromConfig(cfg).Stream(c.Request.Context(), &llm.CompletionRequest{
|
||||
Messages: toLLMMessages(messages),
|
||||
}, func(delta string) {
|
||||
contentBuilder.WriteString(delta)
|
||||
@@ -188,7 +176,7 @@ func writeSSEError(c *gin.Context, code int, message string) {
|
||||
c.Writer.Flush()
|
||||
}
|
||||
|
||||
// TestLLMConnection 测试 LLM 连接(发送一条 ping 消息) // Logan.Li
|
||||
// TestLLMConnection 测试 LLM 连接(询问模型身份并返回回答) // Logan.Li
|
||||
// POST /api/v1/aiops/llm-config/test
|
||||
func (h *LLMHandler) TestLLMConnection(c *gin.Context) {
|
||||
var cfg model.LLMConfig
|
||||
@@ -196,12 +184,22 @@ func (h *LLMHandler) TestLLMConnection(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, model.Response{Code: 400, Message: "请先保存配置"})
|
||||
return
|
||||
}
|
||||
_, err := h.buildLLMClient(cfg).Complete(c.Request.Context(), &llm.CompletionRequest{
|
||||
Messages: []llm.Message{{Role: "user", Content: "ping"}},
|
||||
if !cfg.Enabled {
|
||||
c.JSON(http.StatusOK, model.Response{Code: 400, Message: "请先启用 LLM 服务"})
|
||||
return
|
||||
}
|
||||
resp, err := buildLLMClientFromConfig(cfg).Complete(c.Request.Context(), &llm.CompletionRequest{
|
||||
Messages: []llm.Message{{Role: "user", Content: "你是什么模型?请简短回答。"}},
|
||||
})
|
||||
if err != nil {
|
||||
c.JSON(http.StatusOK, model.Response{Code: 502, Message: "连接失败: " + err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "连接成功"})
|
||||
c.JSON(http.StatusOK, model.Response{Code: 200, Message: "连接成功", Data: gin.H{
|
||||
"answer": resp.Message.Content,
|
||||
"model": resp.Model,
|
||||
"tokens_used": resp.Usage.TotalTokens,
|
||||
"provider": cfg.Provider,
|
||||
"reasoning_enabled": cfg.ReasoningEnabled,
|
||||
}})
|
||||
}
|
||||
Reference in new issue
Block a user