Skip to content

Python: close native generators when stream invocations end - #14701

Open
DiadkoShmek wants to merge 1 commit into
microsoft:mainfrom
DiadkoShmek:fix-native-stream-generator-cleanup
Open

DiadkoShmek wants to merge 1 commit into
microsoft:mainfrom
DiadkoShmek:fix-native-stream-generator-cleanup

Conversation

@DiadkoShmek

Copy link
Copy Markdown

Motivation and Context

Closing a native function's streaming invocation after its first item does not promptly close the underlying generator. With a retained reference to that generator, its finally block remains suspended after the invocation ends. The same occurs when CancelledError is injected into the suspended invocation. A plugin that releases resources in finally therefore keeps them live beyond the closed invocation.

This reproduces through both KernelFunction.invoke_stream() and Kernel.invoke_stream() with ordinary decorated sync/async native functions.

Description

Use closing/aclosing around actual Python generators consumed by KernelFunction.invoke_stream, and close the newly created function-invocation stream owned by Kernel.invoke_stream. Ordinary returned values and custom close-bearing iterable objects retain their current behavior. Public signatures are unchanged.

Validation

Base: 96c9e860db4d7c6da40652d9b421a31b05e98692.

  • Added 18 cases retaining the source generators so garbage collection cannot make cleanup appear correct. They cover direct/Kernel entry, sync/async sources, early aclose, injected cancellation, normal exhaustion, original exception identity and an ordinary close-bearing list that must remain untouched.
  • Identical function/kernel suites against an asserted original-source package root: 8 failed, 148 passed, 4 warnings. Candidate: 156 passed, 4 warnings. Both runs block socket connections; the existing/dependency warnings are unchanged.
  • Independent AI review reran those suites and 33 mocked prompt tests, plus 10 retained-source checks for real task cancellation, awaited async finalizers and cleanup-error priority.
  • Ruff lint/format checks on the three changed files and git diff --check: passed.

Test environment: Python 3.13, local editable source and OpenAI 2.26.0 selected from the repository lockfile; not a complete locked all-connectors environment. Full SDK/integration/provider suites were not run.

Scope: the native-generator invocation path. Consumers still need to close a retained stream when leaving their own iteration body, for example with aclosing. The separate invoke_prompt_stream forwarding layer and deeper provider wrappers are outside this fix; no general provider-resource guarantee is claimed.

Contribution Checklist

  • Added failing-first regression and compatibility coverage.
  • Followed contribution guidance and the existing Python source style.
  • Ran focused local checks with external sockets blocked.
  • Full SDK unit/integration matrix; the executed suites and unchanged warnings are listed above.

AI disclosure: Codex implemented and tested this change, with an independent AI review, as part of an autonomous upstream contribution benchmark. No personal human code review is claimed.

Copilot AI balanced review requested due to automatic review settings October 31, 2026 21:34
@DiadkoShmek
DiadkoShmek requested a review from a team as a code owner October 31, 2026 21:34
@DiadkoShmek
DiadkoShmek deployed to github-app-auth October 31, 2026 21:34 — with GitHub Actions Active
@semantic-kernel-automation semantic-kernel-automation Bot added the python Pull requests for the Python Semantic Kernel label Oct 31, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟢 Approval recommended

No active review issues were identified in the generator-cleanup changes.

No open issues 🎉

What changed in this PR

This PR adds prompt cleanup of native Python generators when streaming invocations end through KernelFunction.invoke_stream() or Kernel.invoke_stream(), without changing public signatures or ordinary return-value behavior.

Changes:

  • Wrap synchronous and asynchronous generators in closing context managers.
  • Close the function-invocation stream owned by Kernel.invoke_stream().
  • Add 18 regression cases covering early closure, injected cancellation, exhaustion, exception identity, and ordinary close-bearing results.
File Description
python/​tests/​unit/​functions/​test_kernel_function_from_method.py Adds retained-generator cleanup and compatibility tests for both entry points.
python/​semantic_kernel/​kernel.py Closes the owned function-invocation stream with aclosing.
python/​semantic_kernel/​functions/​kernel_function.py Uses closing and aclosing when consuming native generators.

Review effort: Balanced

This branch was successfully deployed

1 active deployment
github-app-auth — 02dc31a2 Deployed Oct 31, 2026 by DiadkoShmek via add_label #29523
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Pull requests for the Python Semantic Kernel

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants