Fix truncation issues in piplan, SQLite storage, and history compression; add PIPlanMaxChars configuration

This commit is contained in:
whlaoding
2026-03-15 00:32:14 +08:00
parent ea88e1dc18
commit 38d6875ab8
8 changed files with 683 additions and 66 deletions

View File

@@ -15,6 +15,8 @@ import (
"laodingbot/internal/config"
"laodingbot/internal/llm"
"laodingbot/internal/logger"
"laodingbot/internal/memory"
"strconv"
)
type IncomingMessage struct {
@@ -32,20 +34,26 @@ const (
StreamEventTypeToolResult StreamEventType = "tool_result" // 工具执行结果
StreamEventTypeFinal StreamEventType = "final" // 最终答案
StreamEventTypeError StreamEventType = "error" // 错误信息
StreamEventTypeWorkspaceStart StreamEventType = "workspace_start" // 工具渲染开始
StreamEventTypeWorkspaceDelta StreamEventType = "workspace_delta" // 工具渲染增量内容
StreamEventTypeWorkspaceEnd StreamEventType = "workspace_end" // 工具渲染结束
)
// StreamEvent 代表流式输出中的一个事件
type StreamEvent struct {
Type StreamEventType `json:"type"`
Content string `json:"content"`
Step int `json:"step,omitempty"`
ToolName string `json:"tool_name,omitempty"`
Type StreamEventType `json:"type"`
Content string `json:"content"`
Step int `json:"step,omitempty"`
ToolName string `json:"tool_name,omitempty"`
WorkspaceTitle string `json:"workspace_title,omitempty"` // 仅用于 workspace_start 类型
}
type ChatHandler func(context.Context, IncomingMessage) (string, error)
type StreamChatHandler func(context.Context, IncomingMessage, StreamEventCallback) (string, error)
type StreamEventCallback func(event StreamEvent) error
type UploadHandler func(context.Context, string, string, []llm.InputFile) ([]string, error)
type HistoryHandler func(context.Context, string, int) ([]memory.Message, error)
type Bot struct {
listenAddr string
@@ -55,6 +63,7 @@ type Bot struct {
chatHandler ChatHandler
streamChatHandler StreamChatHandler
uploadHandler UploadHandler
historyHandler HistoryHandler
counter uint64
}
@@ -118,7 +127,7 @@ func NewBot(cfg config.WebUIConfig, log *logger.Logger) (*Bot, error) {
}, nil
}
func (b *Bot) Run(ctx context.Context, chatHandler ChatHandler, streamChatHandler StreamChatHandler, uploadHandler UploadHandler) error {
func (b *Bot) Run(ctx context.Context, chatHandler ChatHandler, streamChatHandler StreamChatHandler, uploadHandler UploadHandler, historyHandler HistoryHandler) error {
if chatHandler == nil {
return fmt.Errorf("nil webui chat handler")
}
@@ -128,11 +137,13 @@ func (b *Bot) Run(ctx context.Context, chatHandler ChatHandler, streamChatHandle
b.chatHandler = chatHandler
b.streamChatHandler = streamChatHandler
b.uploadHandler = uploadHandler
b.historyHandler = historyHandler
mux := http.NewServeMux()
mux.HandleFunc("/api/chat", b.handleChat)
mux.HandleFunc("/api/chat/stream", b.handleChatStream)
mux.HandleFunc("/api/upload", b.handleUpload)
mux.HandleFunc("/api/history", b.handleHistory)
srv := &http.Server{
Addr: b.listenAddr,
@@ -220,6 +231,42 @@ func (b *Bot) handleChat(w http.ResponseWriter, r *http.Request) {
})
}
func (b *Bot) handleHistory(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodGet {
writeJSON(w, http.StatusMethodNotAllowed, errorResponse{Error: "method not allowed"})
return
}
if b.historyHandler == nil {
writeJSON(w, http.StatusInternalServerError, errorResponse{Error: "history handler not ready"})
return
}
sessionID := strings.TrimSpace(r.URL.Query().Get("session_id"))
if sessionID == "" {
writeJSON(w, http.StatusBadRequest, errorResponse{Error: "session_id is required"})
return
}
limitStr := strings.TrimSpace(r.URL.Query().Get("limit"))
limit := 20
if limitStr != "" {
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
limit = l
}
}
history, err := b.historyHandler(r.Context(), sessionID, limit)
if err != nil {
if b.log != nil {
b.log.Errorf("webui history handler failed session_id=%s err=%v", sessionID, err)
}
writeJSON(w, http.StatusInternalServerError, errorResponse{Error: "load history failed"})
return
}
writeJSON(w, http.StatusOK, history)
}
func firstNonEmpty(vals ...string) string {
for _, v := range vals {