refactor: move stripCold to executeTurn, replace clone with rollback pointer

- Remove per-step stripCold from run(); call once per turn in executeTurn
  after accumulator reset and before preamble injection.
- Replace expensive deep-clone snapshot with pre-turn length truncation.
- Delete unused cloneMessages() helper.
This commit is contained in:
Ollie Agent 2026-08-15 11:30:19 +02:00
parent e0f846bd31
commit f61a93e426
3 changed files with 8 additions and 35 deletions

View File

@ -368,35 +368,6 @@ func (s *History) appendUserMessage(content string) {
s.messages = append(s.messages, backend.Message{Role: "user", Content: content})
}
// cloneMessages returns a deep copy of the message slice.
func cloneMessages(msgs []backend.Message) []backend.Message {
out := make([]backend.Message, len(msgs))
for i, m := range msgs {
out[i] = backend.Message{
ID: m.ID,
Role: m.Role,
Content: m.Content,
Reasoning: m.Reasoning,
ToolCallID: m.ToolCallID,
}
if len(m.ContentBlocks) > 0 {
out[i].ContentBlocks = make([]backend.ContentBlock, len(m.ContentBlocks))
copy(out[i].ContentBlocks, m.ContentBlocks)
}
if len(m.ToolCalls) > 0 {
out[i].ToolCalls = make([]backend.ToolCall, len(m.ToolCalls))
for j, tc := range m.ToolCalls {
out[i].ToolCalls[j] = backend.ToolCall{
ID: tc.ID,
Name: tc.Name,
Arguments: append(json.RawMessage(nil), tc.Arguments...),
}
}
}
}
return out
}
// estimateTokens returns a rough token count (~4 chars per token).
func (s *History) estimateTokens() int {
chars := 0

View File

@ -121,9 +121,6 @@ func (ag *Agent) run(ctx context.Context) error {
for {
ag.emit(Event{Role: "state", Content: "thinking"})
if budget := contextBudget(ctx, rt.Backend); budget > 0 && h.estimateTokens() > budget {
h.stripCold(ctx, rt.Backend)
}
history := h.history()

View File

@ -88,9 +88,9 @@ func (ag *Agent) executeTurn(ctx context.Context, input string) string {
// Snapshot messages before this turn modifies them. Restored on context
// overflow so the retry starts from a clean state.
var snapMessages []backend.Message
var preTurnLen int
if ag.history != nil {
snapMessages = cloneMessages(ag.history.messages)
preTurnLen = len(ag.history.messages)
}
if ag.history == nil {
@ -197,6 +197,11 @@ func (ag *Agent) executeTurn(ctx context.Context, input string) string {
ag.history.resetTurnAccumulators()
}
// Strip cold-zone tool results (one batched LLM call per turn).
if ag.history != nil {
ag.history.stripCold(ctx, ag.runtime.Backend)
}
// Inject the preamble system message into history before running.
if ag.history != nil {
ag.history.injectPreamble(ag.runtime.PreambleString())
@ -221,7 +226,7 @@ func (ag *Agent) executeTurn(ctx context.Context, input string) string {
var ctxErr *backend.ContextOverflowError
if !overflowRetried && errors.As(err, &ctxErr) && ag.history != nil {
overflowRetried = true
ag.history.messages = snapMessages
ag.history.messages = ag.history.messages[:preTurnLen]
ag.emit(Event{Role: "info", Content: "context overflow — compacting and retrying...\n"})
ag.SetState("compacting")
if _, cerr := ag.runCompact(ctx, "overflow"); cerr != nil {