Skip to content

fix: prune expired model cooldowns from session state#2

Merged
ShutovKS merged 1 commit into
devfrom
feat/failed-until-cleanup
Jul 13, 2026
Merged

fix: prune expired model cooldowns from session state#2
ShutovKS merged 1 commit into
devfrom
feat/failed-until-cleanup

Conversation

@ShutovKS

Copy link
Copy Markdown
Owner

Проблема

state.failedUntil (Map провайдер→время) накапливал по записи на каждую упавшую модель на всё время жизни сессии и никогда не очищался — микроутечка памяти в долгих сессиях.

Решение

Добавлен pruneExpiredCooldowns(state, now), который удаляет просроченные записи. Вызывается на каждом session.error перед выбором следующей модели.

Тесты

  • Новый тест: после истечения cooldown_ms модель снова доступна как fallback, а просроченные записи удаляются.
  • Юнит-тесты: 36/36 зелёные, typecheck чист.

🤖 Generated with Claude Code

state.failedUntil accumulated one entry per failed model for the lifetime
of a session and was never cleaned up. Expired cooldowns are now pruned on
each session.error, keeping the map bounded.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 13, 2026 23:07
@ShutovKS ShutovKS merged commit 99c5471 into dev Jul 13, 2026
1 check passed
@ShutovKS ShutovKS deleted the feat/failed-until-cleanup branch July 13, 2026 23:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses a small session-state memory leak in the OpenCode model-fallback plugin by pruning expired model cooldown entries from state.failedUntil during error-driven fallback selection.

Changes:

  • Added pruneExpiredCooldowns(state, now) to remove expired entries from the per-session cooldown map.
  • Invoked pruning on each session.error before recording the newly-failed model and selecting the next fallback.
  • Added a test covering that a model becomes selectable again after cooldown_ms elapses.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/plugin.ts Adds and uses pruneExpiredCooldowns during session.error handling to prevent failedUntil from growing unbounded.
test/index.test.ts Adds a cooldown-expiration scenario to validate that previously cooled-down models can be reused.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread test/index.test.ts
expect(prompts).toHaveLength(2)
})

test("#given a model cooldown has expired #when a later error fires #then the model is reusable and stale cooldowns are pruned", async () => {
ShutovKS added a commit that referenced this pull request Jul 14, 2026
Documents all unreleased changes from #2-#9 and the 1.0.8 initial release.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
ShutovKS added a commit that referenced this pull request Jul 14, 2026
PR #3 (suppressed comment): errorText only walked `cause` for Error
instances; plain-object wrappers fell through to JSON.stringify, which
serializes a nested Error to {} and drops retryable text. Walk `cause`
explicitly for records too, with the same depth cap.

PR #2 (inline comment): the prune test only proved an expired cooldown made
the model selectable again — pruning itself was unobservable. Expose active
cooldowns as `cooling` in model_fallback_control status and assert the
expired entries are gone.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
@ShutovKS ShutovKS mentioned this pull request Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants