@@ -11,6 +11,7 @@ import (
1111 "strings"
1212 "sync"
1313 "time"
14+ "unicode"
1415
1516 "github.com/google/uuid"
1617 "github.com/samber/do"
@@ -295,20 +296,13 @@ func (r *tasklogConversationReader) Fetch(ctx context.Context, taskID uuid.UUID,
295296 if maxRounds <= 0 {
296297 maxRounds = 3
297298 }
298- logRounds := maxRounds
299- if strings .TrimSpace (initialContent ) != "" {
300- logRounds --
301- }
302- if logRounds < 0 {
303- logRounds = 0
304- }
305299 const pageSize = 20
306300
307301 var chunks []* tasklog.TurnChunk
308302 userRoundCount := 0
309303 cursor := ""
310304
311- for logRounds > 0 {
305+ for {
312306 resp , err := r .gateway .QueryTurns (ctx , taskID , createdAt , cursor , pageSize , store )
313307 if err != nil {
314308 return nil , fmt .Errorf ("failed to fetch task log history: %w" , err )
@@ -322,7 +316,7 @@ func (r *tasklogConversationReader) Fetch(ctx context.Context, taskID uuid.UUID,
322316 if chunk == nil {
323317 continue
324318 }
325- if (chunk .Event == "user-input" || chunk .Event == "reply-question" ) && userRoundCount >= logRounds {
319+ if (chunk .Event == "user-input" || chunk .Event == "reply-question" ) && userRoundCount >= maxRounds {
326320 stopPaging = true
327321 break
328322 }
@@ -332,7 +326,7 @@ func (r *tasklogConversationReader) Fetch(ctx context.Context, taskID uuid.UUID,
332326 }
333327 }
334328
335- if stopPaging || userRoundCount >= logRounds || ! resp .HasMore || resp .NextCursor == "" {
329+ if stopPaging || userRoundCount >= maxRounds || ! resp .HasMore || resp .NextCursor == "" {
336330 break
337331 }
338332 cursor = resp .NextCursor
@@ -355,9 +349,6 @@ func buildSummaryConversation(ctx context.Context, logger *slog.Logger, taskID u
355349 })
356350
357351 var messages []llm.Message
358- if initialContent != "" {
359- messages = append (messages , llm.Message {Role : "user" , Content : initialContent })
360- }
361352
362353 agentMsg := []string {}
363354 for _ , chunk := range chunks {
@@ -410,21 +401,38 @@ func buildSummaryConversation(ctx context.Context, logger *slog.Logger, taskID u
410401 }
411402 }
412403
413- if len (messages ) == 0 {
414- return nil , errNoConversation
415- }
416-
417404 if len (agentMsg ) > 0 {
418405 agentContent := strings .Join (agentMsg , "" )
419406 messages = append (messages , llm.Message {Role : "assistant" , Content : agentContent })
420407 }
421408
409+ initialContent = strings .TrimSpace (initialContent )
410+ if userRoundCount < maxRounds && initialContent != "" {
411+ messages = append ([]llm.Message {{Role : "user" , Content : initialContent }}, messages ... )
412+ }
413+
414+ if len (messages ) == 0 {
415+ return nil , errNoConversation
416+ }
417+
422418 if logger != nil {
423- logger .DebugContext (ctx , "conversation" , "task_id" , taskID , "messages_count" , len (messages ), "messages " , messages )
419+ logger .DebugContext (ctx , "task summary conversation" , "task_id" , taskID , "messages_count" , len (messages ), "conversation " , formatSummaryConversation ( messages ) )
424420 }
425421 return messages , nil
426422}
427423
424+ func formatSummaryConversation (messages []llm.Message ) []map [string ]any {
425+ conversation := make ([]map [string ]any , 0 , len (messages ))
426+ for i , msg := range messages {
427+ conversation = append (conversation , map [string ]any {
428+ "index" : i ,
429+ "role" : msg .Role ,
430+ "content" : msg .Content ,
431+ })
432+ }
433+ return conversation
434+ }
435+
428436func userInputContent (decoded []byte ) string {
429437 var payload userInputPayload
430438 if err := json .Unmarshal (decoded , & payload ); err == nil && len (payload .Content ) > 0 {
@@ -458,8 +466,8 @@ func (s *TaskSummaryService) generateSummary(ctx context.Context, conversation [
458466- 不超过%d字
459467- 不要标点结尾
460468- 只输出标题,不要解释
461- - 第一条用户消息是任务原始需求,必须优先依据它生成标题
462- - 后续对话只作为补充上下文,不要把上下文交接、压缩摘要或运行状态总结当成任务标题
469+ - 只根据用户的实质需求生成标题,不要根据示例、助手回复或运行状态编造需求
470+ - 如果早期输入为空泛或无意义,但后续用户消息补充了明确需求,以后续明确需求为准
463471- 重点关注用户想要完成什么目标,而不是 AI 问了什么问题
464472- 标题要具体,让人一看就知道用户想做什么
465473 - 如果是开发任务:说明做的是什么应用/功能(如"开发五子棋游戏")
@@ -488,24 +496,23 @@ func (s *TaskSummaryService) generateSummary(ctx context.Context, conversation [
488496
489497func fallbackSummaryFromConversation (conversation []llm.Message , maxChars int ) (string , bool ) {
490498 userInputs := make ([]string , 0 , len (conversation ))
491- hasAssistant := false
492499 for _ , msg := range conversation {
493- switch msg .Role {
494- case "user" :
500+ if msg .Role == "user" {
495501 content := strings .TrimSpace (msg .Content )
496502 if content != "" {
497503 userInputs = append (userInputs , content )
498504 }
499- case "assistant" :
500- if strings .TrimSpace (msg .Content ) != "" {
501- hasAssistant = true
502- }
503505 }
504506 }
505- if hasAssistant || len (userInputs ) != 1 || ! isLowInformationInput ( userInputs [ 0 ]) {
507+ if len (userInputs ) == 0 {
506508 return "" , false
507509 }
508- return truncateSummary (userInputs [0 ], maxChars ), true
510+ for _ , input := range userInputs {
511+ if ! isLowInformationInput (input ) {
512+ return "" , false
513+ }
514+ }
515+ return truncateSummary (userInputs [len (userInputs )- 1 ], maxChars ), true
509516}
510517
511518func isLowInformationInput (input string ) bool {
@@ -515,7 +522,12 @@ func isLowInformationInput(input string) bool {
515522 case "hi" , "hello" , "hey" , "你好" , "您好" , "嗨" , "哈喽" , "hello there" , "ok" , "okay" , "嗯" , "嗯嗯" , "额" :
516523 return true
517524 }
518- return false
525+ for _ , r := range normalized {
526+ if unicode .IsLetter (r ) {
527+ return false
528+ }
529+ }
530+ return true
519531}
520532
521533func truncateSummary (s string , maxChars int ) string {
0 commit comments