@@ -40,8 +40,7 @@ class LargeOutputActor(
4040 model : TextModel = OpenAIModels .GPT4o ,
4141 temperature : Double = 0.3 ,
4242 private val maxIterations : Int = 5 ,
43- private val ellipsisPattern : Regex = Regex ("\\.\\.\\."),
44- private val namedEllipsisPattern : Regex = Regex ("""\.\.\.(? <sectionName>[\w\s]+)\.\.\.""")
43+ private val namedEllipsisPattern : Regex = Regex ("""\.\.\.(? <sectionName>[\w\s-]+? )\.\.\.""")
4544) : BaseActor<List<String>, String>(
4645 prompt = prompt,
4746 name = name,
@@ -67,33 +66,69 @@ class LargeOutputActor(
6766 var accumulatedResponse = " "
6867 var currentMessages = messages.toList()
6968 var iterations = 0
69+ var previousContext = " "
70+ var processedSections = mutableSetOf<String >()
7071
7172 while (iterations < maxIterations) {
7273 val response = response(* currentMessages.toTypedArray(), api = api).choices.first().message?.content
7374 ? : throw RuntimeException (" No response from LLM" )
7475
75- accumulatedResponse + = response.trim()
76+ // Replace the ellipsis in the accumulated response with the new content
77+ if (previousContext.isNotEmpty()) {
78+ val lastEllipsis = namedEllipsisPattern.find(accumulatedResponse)
79+ if (lastEllipsis != null ) {
80+ accumulatedResponse = accumulatedResponse.replaceRange(
81+ lastEllipsis.range.first,
82+ lastEllipsis.range.last + 1 ,
83+ response.trim()
84+ )
85+ }
86+ } else {
87+ accumulatedResponse = response.trim()
88+ }
89+
90+ val matches = namedEllipsisPattern.findAll(response)
91+ .mapNotNull { it.groups[" sectionName" ]?.value }
92+ .filter { it !in processedSections }
93+ .toList()
7694
77- val matches = namedEllipsisPattern.findAll(response).mapNotNull { it.groups[" sectionName" ]?.value }.toList()
7895 if (matches.isNotEmpty()) {
96+ val nextSection = matches.first()
97+ processedSections.add(nextSection)
98+
7999 // Identify the pattern after the ellipsis to continue
80- val continuationRequests = matches.map { name ->
81- " Continue the section '$name ' by expanding the ellipsis."
82- }
83- currentMessages = continuationRequests.map { request ->
100+ val continuationRequest = """
101+ |Previous context:
102+ |$accumulatedResponse
103+ |
104+ |Continue the section '$nextSection ' by expanding the ellipsis.
105+ |Make sure the response flows naturally with the existing content.
106+ |Keep the response focused and avoid creating new ellipsis markers.
107+ """ .trimMargin()
108+ currentMessages = listOf (
84109 ApiModel .ChatMessage (
85110 role = ApiModel .Role .user,
86- content = request .toContentList()
111+ content = continuationRequest .toContentList()
87112 )
88- }
113+ )
114+ previousContext = accumulatedResponse
89115 iterations++
90116 } else {
91117 break
92118 }
93119 }
94120
95121 if (iterations == maxIterations && namedEllipsisPattern.containsMatchIn(accumulatedResponse)) {
96- throw RuntimeException (" Maximum iterations reached. Output may be incomplete." )
122+ throw RuntimeException ("""
123+ |Maximum iterations ($maxIterations ) reached. Output may be incomplete.
124+ |Processed sections: ${processedSections.joinToString(" , " )}
125+ |Remaining ellipsis markers: ${
126+ namedEllipsisPattern.findAll(accumulatedResponse)
127+ .mapNotNull { it.groups[" sectionName" ]?.value }
128+ .joinToString(" , " )
129+ }
130+ |Current length: ${accumulatedResponse.length}
131+ """ .trimMargin())
97132 }
98133
99134 return accumulatedResponse
@@ -106,7 +141,7 @@ class LargeOutputActor(
106141 model = model,
107142 temperature = this .temperature,
108143 maxIterations = this .maxIterations,
109- ellipsisPattern = this .ellipsisPattern
144+ namedEllipsisPattern = this .namedEllipsisPattern
110145 )
111146 }
112147}
0 commit comments