Skip to content

bug: async replies that complete after clear-all repopulate history and usage #80

Description

@JNK234

Problem

clearAll() in LLMExtension.scala clears messageHistory, agentUsage, runUsage and agentProfile under their locks, but nothing invalidates calls that are still in flight. Start llm:chat-async on the observer, call clear-all, then let the reply arrive: its completion callback runs recordUsage and commitExchange, so the previous run's tokens and exchange land in the freshly reset state. The separate history and usage locks also mean a reset can split those two updates.

Found by a Codex review on 2026-09-08. Predates today's changes for history (since #44); token usage (#78) extends the same gap.

Fix

Capture a run generation number when a request is launched; advance it in clearAll(); have recordUsage and commitExchange drop the update when the generation no longer matches. One counter under one lock keeps history and usage consistent.

Test

Start a __TEST_DELAY: async call, clear-all, resolve it with runresult, then assert llm:history is [] and llm:get llm:usage-total "calls" is 0.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions