cherry-pick: fix(mcp): move t.cancel() inside try block (#60213)#3
Merged
Conversation
… /exit
During shutdown, the event loop is closed before MCP tasks finish, so
t.cancel() → call_soon() raises RuntimeError('Event loop is closed').
Moved t.cancel() inside the try block at both locations (keepalive
loop and _wait_for_reconnect_or_shutdown).
Closes NousResearch#60197
(cherry picked from commit 8c7afb4)
Co-authored-by: AIalliAI <285906080+AIalliAI@users.noreply.github.com>
Owner
Author
Review: APPROVE (submitted as comment - unable to approve own PR)Verification
AnalysisThe fix correctly addresses Applied at both cleanup locations in the MCP tool lifecycle management, ensuring consistent behavior. Recommendation: MERGE |
AIalliAI
commented
Jul 7, 2026
AIalliAI
left a comment
Owner
Author
There was a problem hiding this comment.
Hermes Agent Code Review
Verdict: APPROVED (note: cannot self-approve — submitted as comment)
Correctness
- Moving
t.cancel()inside the try block is the right fix: when the event loop is already closed (shutdown via/exit),t.cancel()raisesRuntimeError("Event loop is closed"). Catching it prevents the crash reported in NousResearch#60197. - Applied consistently at both cleanup locations (
_wait_for_lifecycle_eventand_wait_for_reconnect_or_shutdown).
Edge Cases
- Task not cancelled when loop is closed: If
t.cancel()raisesRuntimeError, we skipawait t— but the loop is already closed, so there is nothing to clean up. Acceptable. await talso raising RuntimeError: Now explicitly caught (was previously caught only by the broadExceptionhandler), which is an improvement.- Other exceptions from
t.cancel(): Caught by theexcept Exceptionfallback, identical to the original behavior.
Code Quality
- Splitting
except (CancelledError, RuntimeError)fromexcept Exceptionimproves readability and documents intent. - The
passpattern in both handlers is appropriate for afinallycleanup block — these are best-effort cleanup operations during teardown. - Minimal diff (8 insertions, 4 deletions) — no unnecessary changes.
Cherry-Pick Hygiene
- Author preserved:
webtecnica - Commit message follows conventional format
- Cleanly cherry-picked from upstream NousResearch#60213
Minor Nit (non-blocking)
- The
except (asyncio.CancelledError, RuntimeError): passis technically redundant — theexcept Exception: passbelow would catch both anyway. But the explicit listing serves as documentation that these are the expected exceptions during shutdown.
Reviewed by Hermes Agent
AIalliAI
pushed a commit
that referenced
this pull request
Jul 26, 2026
AIalliAI
pushed a commit
that referenced
this pull request
Jul 26, 2026
Blocking #1 — gateway-connecting-overlay.tsx reduced-motion regression: the top `if (reduce) setPhase('gone')` fired unconditionally on mount whenever reduce-motion was on, so every OS reduced-motion user lost the CONNECTING overlay during cold boot entirely (jumped to 'gone' before the gateway was even open). The intent was to skip the exit *choreography*, not to skip showing the overlay. Removed the unconditional top block and the redundant nested preview block; kept only the third branch (`gatewayState === 'open' && shownRef.current` → `reduce ? 'gone' : 'text-out'`) which correctly gates the short-circuit on connect. Also fixed `if(reduce)` missing-space, 6-space misindent, and the same 3-line comment pasted three times. Nit #1 — tsconfig excludes e2e, so specs were never typechecked in CI. Added tsconfig.e2e.json (extends base, includes e2e/ + playwright.config.ts, adds @playwright/test types) and wired it into the typecheck script. This surfaced three latent type errors that are fixed in the same commit: - fix-electron-tracing.ts: `app._context` and `electron._playwright` are private APIs — added `as any` on the access before the existing cast. - playwright.config.ts: `reducedMotion: 'reduce'` directly under `use:` is not a valid UseOptions property in playwright 1.58; it's a BrowserContextOption accessed via `contextOptions: { reducedMotion: 'reduce' }`. The old form was silently ignored at runtime, so reduced-motion emulation wasn't actually active — screenshots could catch overlays mid-fade (exactly what the comment warned about). Nit #2 — fix-electron-tracing.ts reaches into Playwright internals (_playwright, _allContexts, _context) with no public contract. Added a header comment calling out the `@playwright/test` exact pin (=1.58.2) so a future bump knows to re-verify the private symbols still exist. Nit #3 — main.ts TEST_WORKER_INDEX block had stray 6-space indentation. Verified: tsc -p . && tsconfig.electron && tsconfig.e2e → 0 errors; vitest boot-failure-overlay (3/3) + boot-failure-reauth (21/21) pass; npm run build clean; playwright e2e/boot-failure.spec.ts 2/2 pass.
AIalliAI
pushed a commit
that referenced
this pull request
Jul 26, 2026
…d curator The skill-authoring guide and curator prompt both reference descriptions as the primary discovery mechanism but never mentioned the 57-char system prompt truncation. Add explicit guidance: - Authoring guide: frontmatter docs, template comment, size limits, pitfall #3 with good/bad examples, verification checklist - Curator prompt: parenthetical noting the 57-char window when writing umbrella skill descriptions
AIalliAI
added a commit
that referenced
this pull request
Jul 26, 2026
…l_dirs, indexed lookup Three substantive changes to the kanban create-time skill validator: 1. Mixed valid/invalid skills (review #1): Reject only when ALL requested skills are unresolvable. When some load and some don't, accept the task — matching main's behavior (commit 018009b) of skipping unknown entries and continuing with whatever loaded. 2. Relative external_dirs (review #2): Resolve relative paths in skills.external_dirs against the worker's HERMES_HOME, not the creator cwd. Mirrors get_external_skills_dirs() in agent/skill_utils.py. 3. Shared indexed skill lookup (review #3): Replace raw rglob() with iter_skill_index_files() so excluded paths (VCS, venv, node_modules, cache dirs, skill support dirs) are not counted. Add ambiguity rejection: when a name matches across multiple search roots, treat it as unresolvable — matching skill_view()'s refusal to guess. +6 new tests covering mixed valid/invalid, relative external_dirs, ambiguity rejection, excluded paths, and skill support dir exclusion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cherry-pick of PR NousResearch#60213 from NousResearch/hermes-agent.
Original PR
Changes
Moves
t.cancel()insidetryblock at both cleanup locations intools/mcp_tool.py:_wait_for_lifecycle_eventmethod_wait_for_reconnect_or_shutdownmethodThis prevents
RuntimeError('Event loop is closed')during shutdown when the event loop closes before MCP tasks finish cleanup.Verification