Skip to content

fix(python-client): async method parity and server keepalive timeout#387

Merged
nicoloboschi merged 2 commits intomainfrom
fix/async-parity-and-keepalive
Feb 17, 2026
Merged

fix(python-client): async method parity and server keepalive timeout#387
nicoloboschi merged 2 commits intomainfrom
fix/async-parity-and-keepalive

Conversation

@cdbartholomew
Copy link
Contributor

@cdbartholomew cdbartholomew commented Feb 16, 2026

Summary

  • Server keepalive fix: Set uvicorn timeout_keep_alive to 30s. The default (5s) is shorter than aiohttp's client-side keepalive (15s), causing ServerDisconnectedError when the client reuses a connection the server has already closed.
  • Async method parity: arecall() was missing 6 parameters available in recall() (trace, query_timestamp, include_entities, include_chunks, max_entity_tokens, max_chunk_tokens) and returned list[RecallResult] instead of RecallResponse. areflect() was missing max_tokens and response_schema.
  • New async methods: Added acreate_bank(), aset_mission(), and adelete_bank() — previously only available as sync.

Breaking change: arecall() return type

arecall() now returns RecallResponse instead of list[RecallResult].

This is a bug fix, not a design decision. The old arecall() was an incomplete implementation that:

  1. Silently discarded data — it stripped trace, entities, and chunks from the response by only returning response.results
  2. Couldn't support features — there was no way to request or receive chunks/entities, making the async path functionally inferior to the sync API
  3. Didn't match its own sync counterpart — the sync recall() has always returned RecallResponse, so anyone switching from sync to async would hit a different return type

The return type was wrong from day one relative to the sync API and the underlying OpenAPI spec. As a 0.x library, semver explicitly allows breaking changes before 1.0.

Migration is trivial:

# Before
memories = await client.arecall(bank_id, query)
for m in memories:

# After
response = await client.arecall(bank_id, query)
for m in response.results:

Test plan

  • New unit test verifies uvicorn config has timeout_keep_alive > 15
  • New async integration tests for arecall (5 tests: return type, include_chunks, include_entities, trace, all params)
  • New async integration tests for areflect (2 tests: max_tokens, structured output)
  • New async integration test for adelete_bank
  • All existing tests pass (36/36, excluding pre-existing flaky test_recall_with_tags_any)
  • Pre-commit lint hooks pass

The Python client's async methods were missing parameters available in
their sync counterparts, and the server's default keepalive timeout was
shorter than the client's, causing ServerDisconnectedError on reused
connections.

Server:
- Set uvicorn timeout_keep_alive to 30s (default was 5s). The Python
  client (aiohttp) has a 15s client-side keepalive, so the server must
  hold connections longer to prevent the client from writing to a
  closed socket.

Python client - async method parity:
- arecall(): add trace, query_timestamp, include_entities,
  include_chunks, max_entity_tokens, max_chunk_tokens. Return
  RecallResponse instead of list[RecallResult].
- areflect(): add max_tokens and response_schema.
- acreate_bank(): new async method.
- aset_mission(): new async method.
- adelete_bank(): new async method.

Tests:
- Add test verifying uvicorn keepalive timeout exceeds client default.
- Add async tests for arecall (include_chunks, include_entities, trace,
  full params), areflect (max_tokens, structured output), and
  adelete_bank.
The tag tests were unreliable because:
- Generic content ("Project X meeting notes") was frequently collapsed
  during fact extraction, leaving no memories to recall
- Assertions checked LLM-rewritten text for literal substrings instead
  of checking tags, which is what the tests are actually verifying

Fix: use distinctive, entity-rich content (named people with specific
actions) that reliably survives fact extraction, and assert on tag
membership rather than text content.
@nicoloboschi nicoloboschi changed the title Fix async method parity and server keepalive timeout fix(python-client): async method parity and server keepalive timeout Feb 17, 2026
@nicoloboschi nicoloboschi merged commit 8114ef4 into main Feb 17, 2026
52 of 58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants