fix(context): preserve chronological turn order through pack assembly
Tool-calling loops were rendered as all-assistant-calls-then-all-tool-results with the original task last, causing the model to re-issue the same tool call indefinitely. Two stacked reorderings caused it: - DefaultContextPackBuilder grouped entries by sourceType for per-type compression, discarding a,t,a,t interleaving. - PromptRenderer forced L1 (the live user turn) to render last, pushing the task after the entire transcript. - SessionOrchestrator's tool loop re-fed currentContext.layers.values.flatten() (grouped by layer) each round, compounding the scramble. Add a chronological `ordinal` to ContextEntry, stamped by the builder from input order and restored after grouping/compression (the compressor preserves entry identity, so ordinals survive). PromptRenderer now orders non-system messages by ordinal, with the old L1-last layer priority kept only as a tiebreak so router chat (ordinal 0) is unchanged. The orchestrator keeps a running ordered accumulator instead of reading back the grouped pack. Adds builder + renderer ordering regression tests.
This commit is contained in:
+8
-3
@@ -281,11 +281,16 @@ abstract class SessionOrchestrator(
|
||||
val schemaEntries = buildSchemaEntries(responseFormat, stageId)
|
||||
val steeringEntries = buildSteeringNoteEntries(sessionId)
|
||||
|
||||
// Maintain the running transcript in true chronological order. Reading it back
|
||||
// from currentContext.layers (a Map grouped by layer) would scramble turn order
|
||||
// across rounds; instead we grow our own ordered list and let the builder restamp
|
||||
// ordinals from it each round.
|
||||
var accumulatedEntries = systemPrompt + schemaEntries + promptEntries + steeringEntries
|
||||
val contextPack = contextPackBuilder.build(
|
||||
id = ContextPackId(UUID.randomUUID().toString()),
|
||||
sessionId = sessionId,
|
||||
stageId = stageId,
|
||||
entries = systemPrompt + schemaEntries + promptEntries + steeringEntries,
|
||||
entries = accumulatedEntries,
|
||||
budget = TokenBudget(limit = stageConfig.tokenBudget),
|
||||
)
|
||||
emitContextTruncationIfNeeded(sessionId, stageId, contextPack)
|
||||
@@ -324,12 +329,12 @@ abstract class SessionOrchestrator(
|
||||
retryable = true,
|
||||
)
|
||||
}
|
||||
val allEntries = currentContext.layers.values.flatten() + toolEntries
|
||||
accumulatedEntries = accumulatedEntries + toolEntries
|
||||
currentContext = contextPackBuilder.build(
|
||||
id = ContextPackId(UUID.randomUUID().toString()),
|
||||
sessionId = sessionId,
|
||||
stageId = stageId,
|
||||
entries = allEntries,
|
||||
entries = accumulatedEntries,
|
||||
budget = TokenBudget(limit = stageConfig.tokenBudget),
|
||||
)
|
||||
emitContextTruncationIfNeeded(sessionId, stageId, currentContext)
|
||||
|
||||
Reference in New Issue
Block a user