11import { chat , type ChatTaskWirePayload } from "@trigger.dev/sdk/ai" ;
22import { logger , task , prompts } from "@trigger.dev/sdk" ;
33import { streamText , generateText , tool , dynamicTool , stepCountIs , generateId , createProviderRegistry } from "ai" ;
4- import type { LanguageModel , Tool as AITool , UIMessage } from "ai" ;
4+ import type { LanguageModel , LanguageModelUsage , Tool as AITool , UIMessage } from "ai" ;
55import { openai } from "@ai-sdk/openai" ;
66import { anthropic } from "@ai-sdk/anthropic" ;
77import { z } from "zod" ;
@@ -565,7 +565,27 @@ export const aiChatRaw = task({
565565 }
566566
567567 const stop = chat . createStopSignal ( ) ;
568- const conversation = new chat . MessageAccumulator ( ) ;
568+ const conversation = new chat . MessageAccumulator ( {
569+ compaction : {
570+ shouldCompact : ( { totalTokens } ) => ( totalTokens ?? 0 ) > COMPACT_AFTER_TOKENS ,
571+ summarize : async ( { messages : msgs } ) => {
572+ const resolved = await compactionPrompt . resolve ( { } ) ;
573+ return generateText ( {
574+ model : registry . languageModel ( resolved . model ?? "openai:gpt-4o-mini" ) ,
575+ ...resolved . toAISDKTelemetry ( ) ,
576+ messages : [ ...msgs , { role : "user" as const , content : resolved . text } ] ,
577+ } ) . then ( ( r ) => r . text ) ;
578+ } ,
579+ // Flatten to summary only in the raw task variant
580+ compactUIMessages : ( { summary } ) => [
581+ {
582+ id : generateId ( ) ,
583+ role : "assistant" as const ,
584+ parts : [ { type : "text" as const , text : `[Summary]\n\n${ summary } ` } ] ,
585+ } ,
586+ ] ,
587+ } ,
588+ } ) ;
569589
570590 for ( let turn = 0 ; turn < 100 ; turn ++ ) {
571591 stop . reset ( ) ;
@@ -622,33 +642,7 @@ export const aiChatRaw = task({
622642 ...( useReasoning ? { thinking : { type : "enabled" , budgetTokens : 10000 } } : { } ) ,
623643 } ,
624644 } ,
625- // Low-level compaction using chat.compact() — gives full control
626- // while chat.compact handles the decision tree + stream chunks
627- prepareStep : async ( { messages : stepMessages , steps } ) => {
628- // Custom logic before/around compaction
629- const lastStep = steps . at ( - 1 ) ;
630- if ( lastStep ?. usage . totalTokens ) {
631- logger . info ( "Raw task: step usage" , { totalTokens : lastStep . usage . totalTokens , turn } ) ;
632- }
633-
634- const result = await chat . compact ( stepMessages , steps , {
635- threshold : COMPACT_AFTER_TOKENS ,
636- summarize : async ( msgs ) => {
637- const resolved = await compactionPrompt . resolve ( { } ) ;
638- return generateText ( {
639- model : registry . languageModel ( resolved . model ?? "openai:gpt-4o-mini" ) ,
640- ...resolved . toAISDKTelemetry ( ) ,
641- messages : [ ...msgs , { role : "user" as const , content : resolved . text } ] ,
642- } ) . then ( ( r ) => r . text ) ;
643- } ,
644- } ) ;
645-
646- if ( result . type === "compacted" ) {
647- logger . info ( "Raw task: compacted" , { summary : result . summary . slice ( 0 , 100 ) } ) ;
648- }
649-
650- return result . type === "skipped" ? undefined : result ;
651- } ,
645+ prepareStep : conversation . prepareStep ( ) ,
652646 } ) ;
653647
654648 let response : UIMessage | undefined ;
@@ -673,6 +667,14 @@ export const aiChatRaw = task({
673667
674668 if ( runSignal . aborted ) break ;
675669
670+ // Outer-loop compaction — runs if token threshold exceeded
671+ let turnUsage : LanguageModelUsage | undefined ;
672+ try { turnUsage = await result . totalUsage ; } catch { /* non-fatal */ }
673+ await conversation . compactIfNeeded ( turnUsage , {
674+ chatId : currentPayload . chatId ,
675+ turn,
676+ } ) ;
677+
676678 // Persist messages
677679 await prisma . chat . update ( {
678680 where : { id : currentPayload . chatId } ,
@@ -722,6 +724,26 @@ export const aiChatSession = task({
722724 signal,
723725 idleTimeoutInSeconds : payload . idleTimeoutInSeconds ?? 60 ,
724726 timeout : "1h" ,
727+ compaction : {
728+ shouldCompact : ( { totalTokens } ) => ( totalTokens ?? 0 ) > COMPACT_AFTER_TOKENS ,
729+ summarize : async ( { messages : msgs } ) => {
730+ const resolved = await compactionPrompt . resolve ( { } ) ;
731+ return generateText ( {
732+ model : registry . languageModel ( resolved . model ?? "openai:gpt-4o-mini" ) ,
733+ ...resolved . toAISDKTelemetry ( ) ,
734+ messages : [ ...msgs , { role : "user" as const , content : resolved . text } ] ,
735+ } ) . then ( ( r ) => r . text ) ;
736+ } ,
737+ // Keep summary + last 4 messages in the session variant
738+ compactUIMessages : ( { uiMessages, summary } ) => [
739+ {
740+ id : generateId ( ) ,
741+ role : "assistant" as const ,
742+ parts : [ { type : "text" as const , text : `[Conversation summary]\n\n${ summary } ` } ] ,
743+ } ,
744+ ...uiMessages . slice ( - 4 ) ,
745+ ] ,
746+ } ,
725747 } ) ;
726748
727749 for await ( const turn of session ) {
@@ -754,31 +776,6 @@ export const aiChatSession = task({
754776 ...( useReasoning ? { thinking : { type : "enabled" , budgetTokens : 10000 } } : { } ) ,
755777 } ,
756778 } ,
757- // Low-level compaction — same pattern as raw task
758- prepareStep : async ( { messages : stepMessages , steps } ) => {
759- const lastStep = steps . at ( - 1 ) ;
760- if ( lastStep ?. usage . totalTokens ) {
761- logger . info ( "Session: step usage" , { totalTokens : lastStep . usage . totalTokens , turn : turn . number } ) ;
762- }
763-
764- const result = await chat . compact ( stepMessages , steps , {
765- threshold : COMPACT_AFTER_TOKENS ,
766- summarize : async ( msgs ) => {
767- const resolved = await compactionPrompt . resolve ( { } ) ;
768- return generateText ( {
769- model : registry . languageModel ( resolved . model ?? "openai:gpt-4o-mini" ) ,
770- ...resolved . toAISDKTelemetry ( ) ,
771- messages : [ ...msgs , { role : "user" as const , content : resolved . text } ] ,
772- } ) . then ( ( r ) => r . text ) ;
773- } ,
774- } ) ;
775-
776- if ( result . type === "compacted" ) {
777- logger . info ( "Session: compacted" , { summary : result . summary . slice ( 0 , 100 ) } ) ;
778- }
779-
780- return result . type === "skipped" ? undefined : result ;
781- } ,
782779 } ) ;
783780
784781 await turn . complete ( result ) ;
0 commit comments