fix(python-client): async=true silently ignored on retain (#709)

* docs(claude-code): tidy configuration reference and sync README

Add missing settings (retainMode, retainToolCalls, retainTags,
retainMetadata, embedPackagePath, llmApiKeyEnv, agentName, and
several recall options) that existed in code but not in docs.
Restructure config tables with prose introductions, clearer
descriptions, and consistent layout across both files.

* refactor(claude-code): remove recallTopK setting

Unused client-side cap — Hindsight server already controls result
count via recallBudget and recallMaxTokens.

* fix(python-client): async=true was silently ignored on retain calls

The hand-written client wrapper passed `async_=retain_async` to
RetainRequest, but the generated Pydantic model uses `var_async` as the
Python field name (with `alias="async"`). The `async_` kwarg didn't
match either the field name or the alias, so Pydantic silently ignored
it — every retain call ran synchronously regardless of the flag.

This has been broken since the client was first introduced (6073ac4f),
not a regression.

Also adds unit tests that verify the async field serializes correctly
in the request JSON, preventing future regressions.
This commit is contained in:
Nicolò Boschi 2026-03-26 15:21:43 +01:00 committed by GitHub
parent 91397190c0
commit c9ff37dcbf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 44 additions and 2 deletions

View file

@ -204,7 +204,7 @@ class Hindsight:
request_obj = retain_request.RetainRequest( request_obj = retain_request.RetainRequest(
items=memory_items, items=memory_items,
async_=retain_async, var_async=retain_async,
document_tags=document_tags, document_tags=document_tags,
) )
@ -618,7 +618,7 @@ class Hindsight:
request_obj = retain_request.RetainRequest( request_obj = retain_request.RetainRequest(
items=memory_items, items=memory_items,
async_=retain_async, var_async=retain_async,
document_tags=document_tags, document_tags=document_tags,
) )

View file

@ -0,0 +1,42 @@
"""
Test that RetainRequest correctly serializes the async field.
Regression test for a bug where the client passed async_=True (invalid kwarg)
instead of var_async=True, causing async mode to be silently ignored.
"""
from hindsight_client_api.models.memory_item import MemoryItem
from hindsight_client_api.models.retain_request import RetainRequest
def _make_item():
return MemoryItem(content="test content")
def test_retain_request_async_true_serialized():
"""var_async=True must appear as 'async': True in the serialized dict."""
req = RetainRequest(items=[_make_item()], var_async=True)
d = req.to_dict()
assert d["async"] is True
def test_retain_request_async_false_serialized():
"""var_async=False (default) must appear as 'async': False."""
req = RetainRequest(items=[_make_item()], var_async=False)
d = req.to_dict()
assert d["async"] is False
def test_retain_request_default_is_sync():
"""Omitting var_async should default to synchronous (async=False)."""
req = RetainRequest(items=[_make_item()])
d = req.to_dict()
assert d["async"] is False
def test_retain_request_async_json_roundtrip():
"""async=True must survive a JSON serialization roundtrip."""
req = RetainRequest(items=[_make_item()], var_async=True)
json_str = req.to_json()
restored = RetainRequest.from_json(json_str)
assert restored.var_async is True