HERMES-GIELIE/api
ai-ag2026 4fc51072a2 fix(streaming): pair metering begin_session with end_session teardown (#4633, #2476)
The streaming worker called meter().begin_session(stream_id) but never a
paired end_session. A turn that produced zero output tokens (pre-flight
cancel, or a setup exception before the first token) left a _SessionMeter
in GlobalMeter._sessions forever: get_stats() only prunes sessions with
first_token_ts > 0, so a zero-token session is never reclaimed, and each
leaked entry inflates the `active` count sent over the SSE metering event.

begin_session() and the metering ticker's .start() are now registered as
the first statements inside the worker's outer `try`, and paired with an
idempotent meter().end_session(stream_id, 0) plus a deterministic
_metering_stop.set() in that try's outer `finally` (the same block that
pops STREAMS/CANCEL_FLAGS) — so every exit path tears the session down.
Deferring .start() until after put() is defined also closes a latent
start-before-put ordering window in the ticker closure.

The metering payload is unchanged; end_session only pops the session.

Verification: tests/test_metering_session_lifecycle.py (leak reproduction,
end_session reclaim, idempotency, begin->cancel-before-token->empty) plus a
plain-assert run on python3.11 (conftest gates pytest to 3.11-3.13; system
python is 3.14). py_compile clean.

WARNING streaming-contract: adjusts the streaming worker's begin/end
teardown ordering. Needs RFC/contract review against docs/rfcs/
(session-sse-contract-v1.md) before merge — draft PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 00:51:28 +00:00
..
__init__.py
agent_health.py fix(health): send Bearer auth on remote /health/detailed probe (#5418) 2026-07-02 16:24:39 +00:00
agent_sessions.py fix(sessions): open state.db read-only for lineage reads + watcher projection 2026-07-08 20:17:45 +00:00
auth.py fix(#5578): stop login next= param from nesting into itself and exploding the URL 2026-07-05 00:12:19 +00:00
auth_oidc.py fix(#3825): harden oidc endpoint and claim validation 2026-06-30 20:59:19 -04:00
background.py
background_process.py fix(bg): serialize daemon-thread start under a lifecycle lock 2026-07-08 20:58:18 +00:00
clarify.py stage #4524: clarify 409-terminal (id-guarded, loading-cleared) + SSE-notify on expiry (#4504) + v0.51.534 CHANGELOG 2026-06-20 05:36:56 +00:00
commands.py fix(webui): guard non-dict resolve_moa_preset result in resolve_moa_config 2026-07-01 07:54:48 -05:00
compression_anchor.py Address compaction marker and redaction review 2026-06-26 00:12:09 +00:00
compression_recovery.py Live Stream: add compression recovery action 2026-07-04 21:42:32 +08:00
config.py feat(updates): stable/experimental release channels 2026-07-08 19:25:27 +00:00
crash_visibility.py fix(webui): crash visibility — faulthandler + thread excepthook + exit audit (#4633) 2026-07-01 18:01:39 +00:00
dashboard_probe.py
extensions.py fix: prefer IPv4 for extension gallery downloads to prevent timeout on broken IPv6 2026-07-03 20:26:18 +00:00
gateway_chat.py fix(#5564): mint stable per-message ids so large-session forks align 2026-07-04 22:46:56 +00:00
gateway_restart.py fix(health): preserve restart failure contract and proofs (#5156) 2026-06-29 03:44:06 +00:00
gateway_watcher.py fix(sessions): open state.db read-only for lineage reads + watcher projection 2026-07-08 20:17:45 +00:00
goals.py
helpers.py fix(redaction): memoize deterministic API response redactor 2026-06-29 18:22:18 +00:00
kanban_bridge.py rebase(#2814): resolve i18n onto current master + add kanban_view_* keys to all 13 locales 2026-06-23 23:40:45 +00:00
metering.py
models.py gate 5696 on current master 2026-07-06 20:05:17 +00:00
oauth.py Avoid blocking OAuth flow lock during Codex start 2026-06-17 00:20:49 +00:00
office_documents.py #5142: office-doc preview + safe docx editing (#540), rebased on master; optional deps 2026-07-02 01:15:57 +00:00
onboarding.py feat(#3260): self-hosted provider setup (Ollama/LM Studio) in Settings (i18n complete) 2026-07-02 08:17:44 +00:00
passkeys.py Release v0.51.270 — Release IL (stage-u1 — un-hold batch: #3517 #3624 #3613) (#3674) 2026-06-05 11:35:26 -07:00
paths.py fix(profiles): avoid config import cycle 2026-06-01 05:05:16 +00:00
plugin_providers.py Release v0.51.270 — Release IL (stage-u1 — un-hold batch: #3517 #3624 #3613) (#3674) 2026-06-05 11:35:26 -07:00
plugins.py fix(#2622): plugin card UX — legible Open button, single badge, visible toggle + reject protocol-relative tab.path 2026-06-02 03:58:02 +00:00
profiles.py fix(#5696): revert profiles cache TTL 60s->4s (stale profile rows); contributor-flagged follow-up 2026-07-06 20:40:08 +00:00
providers.py feat(#3260): self-hosted provider setup (Ollama/LM Studio) in Settings (i18n complete) 2026-07-02 08:17:44 +00:00
request_diagnostics.py fix(webui): preserve user_message_count under DB contention 2026-07-06 18:34:02 +00:00
rollback.py fix(#4410): pre-check workspace leaf type via lstat + close fd on non-regular (Codex gate v2) 2026-06-18 19:22:29 +00:00
route_approvals.py fix(#5000): relay mirrored gateway approvals after stream loss 2026-06-27 06:03:24 +00:00
route_session_list_cache.py feat: add Webhooks sidebar filter parity 2026-06-30 17:06:31 +00:00
routes.py fix(updates): thread offered channel through apply/force to close the debounce race 2026-07-08 22:42:54 +00:00
run_journal.py Fix run-journal writer-lock cache leak on session delete 2026-07-08 21:13:32 +00:00
runner_client.py fix(gateway): correct approval URL and thread session history into runs API (#4479) 2026-06-19 13:16:39 -04:00
runtime_adapter.py Stage 398: PR #2696 — feat(runtime): add runner-local adapter selection (RuntimeAdapter slice 4c, feature-flagged) 2026-05-21 17:43:54 +00:00
session_discoverability.py Merge PR #3048 2026-05-28 17:47:33 +00:00
session_events.py feat(sessions): carry changed session_id in session-list-changed events (#4221) (#4233) 2026-06-15 00:10:01 -07:00
session_export_html.py #4968: export chat to self-contained themed HTML, rebased on master 2026-07-02 02:36:09 +00:00
session_lifecycle.py fix(#5543): fire-and-forget commit_session_memory + drain-safe managed stop 2026-07-04 21:40:21 +00:00
session_ops.py fix(#5563): align forked context to display for large (compacted) sessions 2026-07-04 20:55:06 +00:00
session_recovery.py Merge latest master into compression recovery action 2026-07-05 10:23:15 +08:00
skill_usage.py fix: remove webui-side writer to avoid conflict with agent 2026-05-27 20:57:32 +08:00
sse_chunked.py stage #4447: opt-in chunked SSE for buffering proxies (#4447) + v0.51.524 CHANGELOG 2026-06-19 22:09:17 +00:00
startup.py
state_sync.py fix(state-sync): mirror WebUI API call counts 2026-07-07 19:48:19 +00:00
streaming.py fix(streaming): pair metering begin_session with end_session teardown (#4633, #2476) 2026-07-09 00:51:28 +00:00
system_health.py fix: keep psutil optional for system health 2026-06-26 20:49:13 +00:00
terminal.py Release v0.51.304 — Release JT (stage-p2a — un-held terminal reaper + opt-in Docker GPU) (#3757) 2026-06-06 18:04:16 -07:00
todo_state.py Release v0.51.261 — Release IC (stage-r11) (#3616) 2026-06-04 16:46:20 -07:00
turn_journal.py Release v0.51.326 — Release KP (#3618 + #3802 + #3762 + #3810) (#3816) 2026-06-07 23:18:51 -07:00
updates.py fix(updates): apply_clear_lock preserves the configured channel 2026-07-08 19:53:32 +00:00
upload.py fix(auth): enforce active-profile session IDs 2026-06-30 04:28:15 +00:00
usage.py
webui_session_db.py fix: preserve compression recovery child markers in sidecar rebuild 2026-07-05 06:45:50 +08:00
workspace.py #5142: office-doc preview + safe docx editing (#540), rebased on master; optional deps 2026-07-02 01:15:57 +00:00
workspace_git.py fix(workspace-git): hide git subprocess console windows on Windows (#5692) 2026-07-07 02:07:39 +00:00
worktrees.py