Skip to content

fix: avoid nil session dereference in OpenAI local mode#2233

Open
anxkhn wants to merge 1 commit into
kagent-dev:mainfrom
anxkhn:fix/openai-local-nil-session
Open

fix: avoid nil session dereference in OpenAI local mode#2233
anxkhn wants to merge 1 commit into
kagent-dev:mainfrom
anxkhn:fix/openai-local-nil-session

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 14, 2026

Copy link
Copy Markdown
Contributor
## What

The OpenAI agent executor crashes on every request when the A2A server is run
in local mode.

`KAgentApp.build_local()` constructs the executor with `session_factory=None`
(`python/packages/kagent-openai/src/kagent/openai/_a2a.py`), so `execute()`
leaves `session` as `None`. `_stream_agent_events` then built the
`SessionContext` with `session.session_id` unconditionally:

```python
session_context = SessionContext(session_id=session.session_id)

That dereference raises AttributeError: 'NoneType' object has no attribute 'session_id' before the agent runs, so no local-mode request ever reaches the
model.

Fix

Fall back to the A2A context id when there is no session:

session_id = session.session_id if session else context.context_id
session_context = SessionContext(session_id=session_id)

context.context_id is already how execute() derives the session id
(getattr(context, "session_id", None) or context.context_id) and is the
identifier used throughout this executor, so the SessionContext stays
consistent and stable per A2A conversation.

Testing

Added python/packages/kagent-openai/tests/test_agent_executor.py, which builds
the executor with session_factory=None and drives execute():

  • one test asserts the run reaches Runner.run_streamed (before the fix it
    fails with the AttributeError above),
  • one test asserts the SessionContext id falls back to context.context_id.

Both fail on main and pass with the fix.

cd python
uv run pytest packages/kagent-openai/tests/test_agent_executor.py

The OpenAI agent executor built by KAgentApp.build_local() is constructed
with session_factory=None, so execute() streams events with session=None.
_stream_agent_events then built SessionContext(session_id=session.session_id)
unconditionally, raising AttributeError before the agent ran and failing every
local-mode A2A request with "'NoneType' object has no attribute 'session_id'".

Fall back to the A2A context id when there is no session, matching the session
identifier already used elsewhere in this executor. Add regression tests that
exercise execute() with session_factory=None.

Signed-off-by: Anas Khan <83116240+anxkhn@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 14, 2026 00:12
@anxkhn anxkhn requested a review from a team as a code owner July 14, 2026 00:12
@github-actions github-actions Bot added the bug Something isn't working label Jul 14, 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.

Pull request overview

Fixes a crash in the OpenAI A2A agent executor when running in local mode (where session_factory=None) by avoiding dereferencing session.session_id when session is None, and adds regression tests to ensure local-mode execution reaches the runner and uses a stable session identifier.

Changes:

  • Update _stream_agent_events() to derive a SessionContext.session_id even when session is None.
  • Add async tests covering execute() behavior when session_factory=None, including validating the SessionContext id fallback.

Reviewed changes

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

File Description
python/packages/kagent-openai/src/kagent/openai/_agent_executor.py Avoids None session dereference by computing a fallback session id for SessionContext.
python/packages/kagent-openai/tests/test_agent_executor.py Adds regression tests for local-mode execution and SessionContext session id fallback behavior.

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

Comment on lines +113 to +116
# In local mode there is no session_factory, so session is None; fall back to
# the A2A context id, which is the session identifier used elsewhere here.
session_id = session.session_id if session else context.context_id
session_context = SessionContext(session_id=session_id)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I agree with this comment - check for the session_id on context first, and then fallback to context_id, so it's same as in execute

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants