Skip to main content

adk-null-session

An invocation-local session service for Google ADK. It returns independent Session objects without retaining them in the service. Use it when every request supplies all the information needed to finish in a single Runner invocation, including any ordinary function-call round trips.

Version 0.1.0 is an initial experimental package. It is not a transparent replacement for a history-preserving session service.

Install

From this checkout (Python 3.11 or newer):

python -m pip install .

The runtime dependency is google-adk>=1.27.0,<3. This range targets both ADK 1.x and 2.x; it does not claim that every release or dependency combination has been tested. The package does not directly require A2A SDK. Install the A2A extras appropriate to your ADK version separately if your server uses A2A.

Use with Runner

This example runs locally without model credentials or network calls:

import asyncio

from google.adk.agents.base_agent import BaseAgent
from google.adk.events.event import Event
from google.adk.runners import Runner
from google.genai import types

from adk_null_session import NullSessionService


class EchoAgent(BaseAgent):
    async def _run_async_impl(self, ctx):
        yield Event(
            author=self.name,
            invocation_id=ctx.invocation_id,
            content=types.Content(
                role="model",
                parts=[types.Part(text=ctx.session.state["request_text"])],
            ),
        )


async def main():
    runner = Runner(
        app_name="example",
        agent=EchoAgent(name="echo"),
        session_service=NullSessionService(),
    )
    async for event in runner.run_async(
        user_id="user",
        session_id="request-1",
        new_message=types.Content(
            role="user", parts=[types.Part(text="Hello")]
        ),
        state_delta={"request_text": "Hello"},
    ):
        if event.content:
            for part in event.content.parts or []:
                if part.text:
                    print(part.text)


asyncio.run(main())

create_session() is optional for this service: get_session() accepts any ID. If you call create_session(state=...), that state exists only in its returned object. Runner retrieves a new empty object through get_session(), so the initial state is lost before the first invocation. Pass per-request values through run_async(state_delta=...), as above, or include them in the request.

Explicit URI registration

from google.adk.cli.service_registry import get_service_registry
from adk_null_session import NullSessionService, register_null_session_service

register_null_session_service()
service = get_service_registry().create_session_service("null://")
assert isinstance(service, NullSessionService)

Call registration in the same Python process before building your ADK server and selecting null:// as its session service URI. You can also pass an explicit ServiceRegistry instance to register_null_session_service(registry). The factory ignores URI contents and keyword arguments. Registration replaces any existing null factory in that registry. Installing or importing the package does not register a URI scheme, start uvicorn, or configure logging. Running an unrelated adk web --session_service_uri null:// process after installation alone will not perform this registration.

Behavior

API Result
create_session(...) New unsaved session; trims a supplied ID or generates a UUID for a missing/blank ID. Copies supplied initial state.
get_session(...) New, empty, independent session with exactly the requested ID on every call; event filters have no stored events to filter.
list_sessions(...) Empty ListSessionsResponse.
delete_session(...) No operation. A later lookup still returns an empty session.
get_user_state(...) New empty dictionary, including on ADK versions predating the base API.
append_event(session, event) Inherited ADK behavior: updates the supplied session's events and state during the invocation; partial events are not committed.

The service holds no session references. Ordinary function calling, tool state, and agent output_key values remain available within a single invocation. app: and user: state are also invocation-local; neither is shared across requests. Duplicate IDs are accepted. Unknown and deleted IDs look like empty sessions, so this service cannot support existence checks, session browsing, or tools such as Web UI history/evaluation that require stored sessions.

The inherited append_event does not advance last_update_time in the tested ADK releases. The timestamp records construction time, not the latest event. Events and state still occupy memory and can grow during an invocation.

Limitations that affect correctness

  • No multi-turn memory. Each request must carry the full information it needs. RemoteA2aAgent can reuse a returned context_id without sending earlier history. Even full_history_when_stateless=True does not force full history when a context ID exists in the tested releases. Replacing an A2A server's session store can therefore silently remove context needed by later turns.
  • No continuation. Human-in-the-loop approval, additional authentication, follow-up results for LongRunningFunctionTool, resume, and rewind require history this service discards. In tested ADK 1.x, resuming by invocation_id alone raises a missing-history error. In ADK 2.13.0, an LlmAgent can instead invoke its model again; a scripted repeated tool request reproduced duplicate execution (the in-memory control executed once). Do not use this service for these flows. The service cannot reliably detect resume from get_session arguments, which contain no invocation ID, and does not provide a resume guard.
  • No server-wide retention or memory guarantee. A2A's InMemoryTaskStore is separate. In a ten-request probe, all ten completed Tasks still held history and artifacts. Other stores, logs, traces, caller references, and active invocations can retain data independently. Configure their policies separately.

Compatibility and verification

The initial minimum is ADK 1.27.0, rather than all 1.x versions. In 1.25.0, base append_event fails to pass temp:output_key to a later agent; the same failure occurs with InMemorySessionService. It was fixed by upstream commit 2780ae2 and the probe passes on 1.27.0, 1.39.1, and 2.13.0. Python >=3.11 is chosen to cover the minimum required by the tested ADK 2.x release.

The original implementation was reviewed against source tags 1.25.0, 1.27.0, 1.39.1, and 2.13.0: 89 passed, 3 skipped over 23 cases per tag. The probes include assertions of unsupported behavior, so passing does not certify suitability for those flows. This package adds an explicit empty get_user_state implementation and copies initial state. Its tests preserve the behavior probes and add checks for the package API. The installed 0.1.0 wheel passed 31 tests per tag (93 total) on 1.27.0, 1.39.1, and 2.13.0; the Runner example above also ran successfully on each tag.

The original and package source-tag checks use Python 3.13.18, a shared environment with a2a-sdk 0.3.25, google-genai 2.20.0, and pydantic 2.13.4. They exercise real Runner/tool/A2A handler code with scripted model responses, 20 concurrent invocations, and session-reference release. This is a source behavior check, not a resolved dependency matrix: for example, that shared google-genai version falls outside the declared ranges of ADK 1.27.0 and 2.13.0. No external LLM, HTTP transport, full dependency matrix, other Python version, or production load test was exercised.

Development

The project follows cookiecutter-develop-pypackage 0.4.0, with project_dir_name=adk-null-session, package_name=adk_null_session, and use_taskipy=no. It uses setuptools and reads the package version from adk_null_session.__version__. The existing Apache-2.0 license and service implementation are retained; no command-line application is provided.

Create an isolated environment and run the same checks used in CI:

python -m venv .venv
source .venv/bin/activate
python -m pip install -U pip
python -m pip install -e '.[dev]'
ruff check .
python -m pytest -v
python -m build
python -m twine check --strict dist/*

The dev extra includes pytest-randomly, async/A2A test dependencies, Ruff, build, and twine. The smaller test and test-a2a extras remain available. CI runs on pushes and pull requests using Python 3.11–3.14 with freshly resolved dependencies. A green CI run checks that resolved environment; it does not establish compatibility with every ADK release in the declared dependency range.

In addition to the earlier shared-environment probes, template integration was verified in a fresh Python 3.13.18 environment with installed google-adk 2.13.0, google-genai 2.34.0, pydantic 2.14.2, and a2a-sdk 0.3.26: all 31 tests passed. Other Python versions in the CI matrix have not been run locally.

A2A-specific tests skip when A2A SDK is unavailable. Tests make no external model calls. Build artifacts include the implementation and tests, not exported ADK source trees. The public API is NullSessionService and register_null_session_service from adk_null_session.

Based on the author's article. Licensed under the existing Apache License 2.0.

Release preparation

Update __version__ in src/adk_null_session/__init__.py and the version stated in this README, then run the development checks and review the built wheel and source distribution. Commit the intended release changes and wait for CI to pass before publishing a release.

Before the first upload, configure these external settings manually:

  1. Create the GitHub repository environment named pypi and configure its protection rules as appropriate for releases.
  2. On PyPI, configure a Trusted Publisher (or a pending publisher for the first release) for project adk-null-session, owner ftnext, repository adk-null-session, workflow filename publish.yml, and environment pypi. See the PyPI instructions.

Publishing a GitHub Release tagged v0.1.0 triggers .github/workflows/publish.yml. For later releases, the tag must be v followed by the package version. Its build job creates and checks both distributions and rejects a mismatched release tag. A separate job downloads those artifacts and uploads them to PyPI using OIDC; only this job has id-token: write. No PyPI API token is required. This workflow is for PyPI, not TestPyPI.

Adding these files does not configure a PyPI publisher or perform an upload. Tagging, publishing the GitHub Release, and completing external setup are separate maintainer actions. The workflow has been validated locally; the GitHub-hosted job and actual OIDC upload still need verification during a release.

After changing workflow actions, run pinact run -u, review the updated action versions and full SHA pins, and run actionlint. The PyPI publishing action uses a versioned release tag comment because pinact cannot resolve the template's release/v1 branch.

Metadata

Release files for adk-null-session 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for adk-null-session 0.1.0
File Size Uploaded Provenance Actions
adk_null_session-0.1.0.tar.gz 21.0 kB With provenance Details for adk_null_session-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for adk-null-session 0.1.0
File Interpreter ABI Platform Actions
adk_null_session-0.1.0-py3-none-any.whl Python 3 none any Details for adk_null_session-0.1.0-py3-none-any.whl

Total release size: 33.8 kB

Release files / adk_null_session-0.1.0.tar.gz

Download URL adk_null_session-0.1.0.tar.gz
Size 21.0 kB
Tags Source
SHA-256 checksum
How to use checksums
bfdf991f8062ba11d99655a8be87d8ec9d057b1748376b72a065ea32ac420091
BLAKE2b-256 checksum
How to use checksums
d41ea6569ba8fa0eee725d15ce4626f67198354f76157d21c1948c836de843a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Release files / adk_null_session-0.1.0-py3-none-any.whl

Download URL adk_null_session-0.1.0-py3-none-any.whl
Size 12.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e9e7fcf517bbc5f234fefe600c3b18202f3850f86cae6e535fb60d4d506242f1
BLAKE2b-256 checksum
How to use checksums
5e06e8816f7581e426e8321b7683fa458b2d26811d1a3d488891761f170c8c19
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

Security for adk-null-session 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for adk_null_session-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page