Skip to main content

InfoLang BaseMemoryService for Google ADK agents.

Project description

infolang-adk

InfoLang memory for Google ADK agents: InfoLangMemoryService, a google.adk.memory.BaseMemoryService implementation backed by the InfoLang memory API.

Why this exists

ADK's BaseMemoryService ABC declares two required async methods (search_memory, add_session_to_memory) and two optional ones (add_events_to_memory, add_memory) that default to raising NotImplementedError. Most third-party memory integrations for agent frameworks wrap their SDK as a function-tool the LLM calls, rather than implementing the framework's actual memory-service interface — see mem0ai/mem0#3999, where the maintainers confirm their ADK integration does exactly this. That approach skips Runner-level memory wiring (auto session ingestion, load_memory tool auto-registration, etc.) entirely.

infolang-adk implements the real interface: all four methods, including the two optional ones, backed by real InfoLang calls, not stubs.

Install

pip install infolang-adk

Requires Python 3.11+, google-adk>=1.0.0, and an InfoLang API key.

Quickstart

from google.adk.agents import Agent
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
from infolang_adk import InfoLangMemoryService

memory_service = InfoLangMemoryService(api_key="il_live_...")

agent = Agent(
    name="assistant",
    model="gemini-2.0-flash",
    instruction="You are a helpful assistant with long-term memory.",
)

runner = Runner(
    agent=agent,
    app_name="my_app",
    session_service=InMemorySessionService(),
    memory_service=memory_service,
)

Runner calls add_session_to_memory when a session ends and exposes search_memory to agents that use ADK's built-in load_memory tool (or call it directly, e.g. from a before_agent_callback). See examples/ for a runnable end-to-end agent.

Credentials resolve the same way as the infolang SDK: pass api_key= explicitly, or set the INFOLANG_API_KEY environment variable and construct InfoLangMemoryService() with no arguments. Any keyword InfoLangMemoryService doesn't recognize (base_url=, dev_key=, workspace=, ...) is forwarded verbatim to infolang.AsyncInfoLang(...); see that class for the full list.

To reuse an existing client instead:

from infolang import AsyncInfoLang
from infolang_adk import InfoLangMemoryService

client = AsyncInfoLang(api_key="il_live_...")
memory_service = InfoLangMemoryService(client=client)
# ... use memory_service ...
await memory_service.aclose()  # only closes clients infolang-adk constructed itself

Passing an existing client= means infolang-adk never closes it — close it yourself (or use async with AsyncInfoLang(...) as client:).

Namespace scoping

InfoLang namespaces are a single flat string per memory bank. ADK scopes memory two-dimensionally, by (app_name, user_id). infolang-adk collapses that pair into one namespace per default scheme:

{namespace_prefix}-{sanitized app_name}-{sanitized user_id}

namespace_prefix defaults to "adk". Both segments are sanitized to [a-zA-Z0-9_.-] (anything else, including / and :, becomes -) because app_name/user_id end up in InfoLang recall/list-memory query strings. Two different (app_name, user_id) pairs whose sanitized forms are identical share a namespace — e.g. ("team/a", "u1") and ("team a", "u1") both sanitize to adk-team-a-u1. If that collision risk matters for your app_name/user_id values, supply your own mapping:

memory_service = InfoLangMemoryService(
    api_key="il_live_...",
    namespace_for=lambda app_name, user_id: f"prod-{app_name}-{user_id}",
)

Every InfoLang API call infolang-adk makes is scoped to the namespace for the app_name/user_id of the request that triggered it — one user's agent session never reads or writes another user's memories through this service (scoping only fails if InfoLang's own API-key/workspace boundary is misconfigured upstream; namespace scoping happens after that boundary, not instead of it).

What each method actually does

  • search_memory(app_name, user_id, query) — one InfoLang recall call scoped to the namespace, IL-cosine ranked, top search_top_k (default 10) chunks. Not keyword/full-text search. A namespace with nothing written to it yet returns an empty result rather than raising. min_score= filters out low-confidence chunks client-side (InfoLang's SDK treats scores below 0.85 as a weak match; this class does not enforce that threshold for you — set min_score=0.85 if you want it enforced).
  • add_session_to_memory(session) — ingests every event in the session that has non-empty text content, one remember_batch call. Re-ingesting the same session (e.g. because it gets called again after more turns) stores the events again rather than deduplicating or updating in place — InfoLang has no update-in-place primitive for remember. If you call this repeatedly on a growing session, you'll get duplicate memories for already-ingested turns; use add_events_to_memory with only the new events instead.
  • add_events_to_memory(app_name, user_id, events, session_id=None, custom_metadata=None) — ingests an explicit delta of events (does not require the full session object). custom_metadata scalar values become InfoLang tags ("key:value"); non-scalar values are dropped, since InfoLang's remember has no structured-metadata field, only string tags.
  • add_memory(app_name, user_id, memories, custom_metadata=None) — ingests explicit MemoryEntry items directly (no event/session framing). Entries with no text content raise ValueError; InfoLang only stores text.

Every InfoLang API error other than "namespace not found" (which search_memory treats as empty results) propagates to the caller as the infolang SDK's typed exceptions (AuthenticationError, ValidationError, RateLimitError, ServerError, ...) — this package does not swallow or retry them.

Development

pip install -e ".[dev]"
ruff check .
mypy src/infolang_adk
pytest

Unit tests mock the HTTP layer (no live InfoLang calls). An optional live smoke test (tests/test_live_smoke.py) runs only when INFOLANG_API_KEY is set, and only ever writes to namespaces prefixed ittest-adk-, which it deletes afterward.

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

infolang_adk-0.1.0.tar.gz (17.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

infolang_adk-0.1.0-py3-none-any.whl (13.9 kB view details)

Uploaded Python 3

File details

Details for the file infolang_adk-0.1.0.tar.gz.

File metadata

  • Download URL: infolang_adk-0.1.0.tar.gz
  • Upload date:
  • Size: 17.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for infolang_adk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 8a264806710cce08db5e18e98cc54d55618f99f4704c576ea2733bcb2fe4b4c5
MD5 c80124d2a6a470b3892d66e726c830b2
BLAKE2b-256 caff323c6a746c28dd5575eefe01f4ae9cdd875a440e7ae12728c1ca3f7bb5a3

See more details on using hashes here.

File details

Details for the file infolang_adk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: infolang_adk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 13.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.28 {"installer":{"name":"uv","version":"0.11.28","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for infolang_adk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 a9bf45ed114e26f3dc7513c665d5e38366bba6b8d82264923d264b9606e24546
MD5 6e405d7da8a8a5c207e866d3e75cb9bd
BLAKE2b-256 0816aa86425af59283427e4a2a2ea2fe66672a0973cf1ccbe5d562828f1792f1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page