docs(python-client): async-first pydoc + low-level API access + missing params (#711)
* docs(python-client): improve pydoc strings for async-first usage and low-level API access - Class docstring now clearly documents async-first pattern: a* methods preferred, sync wrappers for scripts/REPLs only - Every sync method docstring points to its async counterpart - Every async method docstring says "preferred" - Expose 10 low-level API properties (documents, entities, operations, webhooks, monitoring, etc.) so agents/users can discover the full API surface without guessing at _-prefixed internals - Add missing API parameters: tag_groups (recall/reflect), fact_types, exclude_mental_models, exclude_mental_model_ids (reflect), observation_scopes/strategy (retain items), background (create_bank) - Fix areflect missing include_facts param that sync reflect already had - Sync recall/reflect now delegate to async counterparts (no logic duplication) * style(retain): format long function call arguments one-per-line
This commit is contained in:
parent
200bab233e
commit
a0cea84d82
3 changed files with 444 additions and 158 deletions
|
|
@ -127,9 +127,7 @@ async def _insert_facts_and_links(
|
||||||
if unit_ids:
|
if unit_ids:
|
||||||
# Process entities
|
# Process entities
|
||||||
step_start = time.time()
|
step_start = time.time()
|
||||||
user_entities_per_content = {
|
user_entities_per_content = {idx: content.entities for idx, content in enumerate(contents) if content.entities}
|
||||||
idx: content.entities for idx, content in enumerate(contents) if content.entities
|
|
||||||
}
|
|
||||||
entity_links = await entity_processing.process_entities_batch(
|
entity_links = await entity_processing.process_entities_batch(
|
||||||
entity_resolver,
|
entity_resolver,
|
||||||
conn,
|
conn,
|
||||||
|
|
@ -217,9 +215,7 @@ async def _extract_and_embed(
|
||||||
embeddings = await embedding_processing.generate_embeddings_batch(embeddings_model, augmented_texts)
|
embeddings = await embedding_processing.generate_embeddings_batch(embeddings_model, augmented_texts)
|
||||||
log_buffer.append(f" Generate embeddings: {len(embeddings)} embeddings in {time.time() - step_start:.3f}s")
|
log_buffer.append(f" Generate embeddings: {len(embeddings)} embeddings in {time.time() - step_start:.3f}s")
|
||||||
|
|
||||||
processed_facts = [
|
processed_facts = [ProcessedFact.from_extracted_fact(ef, emb) for ef, emb in zip(extracted_facts, embeddings)]
|
||||||
ProcessedFact.from_extracted_fact(ef, emb) for ef, emb in zip(extracted_facts, embeddings)
|
|
||||||
]
|
|
||||||
|
|
||||||
return extracted_facts, processed_facts, chunks, usage
|
return extracted_facts, processed_facts, chunks, usage
|
||||||
|
|
||||||
|
|
@ -268,23 +264,56 @@ async def retain_batch(
|
||||||
# --- Delta retain: check if we can skip unchanged chunks ---
|
# --- Delta retain: check if we can skip unchanged chunks ---
|
||||||
if is_first_batch:
|
if is_first_batch:
|
||||||
delta_result = await _try_delta_retain(
|
delta_result = await _try_delta_retain(
|
||||||
pool, embeddings_model, llm_config, entity_resolver, format_date_fn,
|
pool,
|
||||||
bank_id, contents_dicts, contents, config, document_id, fact_type_override,
|
embeddings_model,
|
||||||
document_tags, agent_name, log_buffer, start_time, operation_id, schema, outbox_callback,
|
llm_config,
|
||||||
|
entity_resolver,
|
||||||
|
format_date_fn,
|
||||||
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
config,
|
||||||
|
document_id,
|
||||||
|
fact_type_override,
|
||||||
|
document_tags,
|
||||||
|
agent_name,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
|
operation_id,
|
||||||
|
schema,
|
||||||
|
outbox_callback,
|
||||||
)
|
)
|
||||||
if delta_result is not None:
|
if delta_result is not None:
|
||||||
return delta_result
|
return delta_result
|
||||||
|
|
||||||
# --- Full retain path ---
|
# --- Full retain path ---
|
||||||
extracted_facts, processed_facts, chunks, usage = await _extract_and_embed(
|
extracted_facts, processed_facts, chunks, usage = await _extract_and_embed(
|
||||||
contents, llm_config, agent_name, config, embeddings_model, format_date_fn,
|
contents,
|
||||||
fact_type_override, log_buffer, pool, operation_id, schema,
|
llm_config,
|
||||||
|
agent_name,
|
||||||
|
config,
|
||||||
|
embeddings_model,
|
||||||
|
format_date_fn,
|
||||||
|
fact_type_override,
|
||||||
|
log_buffer,
|
||||||
|
pool,
|
||||||
|
operation_id,
|
||||||
|
schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
if not extracted_facts:
|
if not extracted_facts:
|
||||||
await _handle_zero_facts_documents(
|
await _handle_zero_facts_documents(
|
||||||
pool, bank_id, contents_dicts, contents, config, document_id,
|
pool,
|
||||||
is_first_batch, document_tags, chunks, log_buffer, start_time,
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
config,
|
||||||
|
document_id,
|
||||||
|
is_first_batch,
|
||||||
|
document_tags,
|
||||||
|
chunks,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
)
|
)
|
||||||
return [[] for _ in contents], usage
|
return [[] for _ in contents], usage
|
||||||
|
|
||||||
|
|
@ -336,8 +365,13 @@ async def retain_batch(
|
||||||
contents_dicts, document_tags, doc_contents=doc_contents
|
contents_dicts, document_tags, doc_contents=doc_contents
|
||||||
)
|
)
|
||||||
await fact_storage.handle_document_tracking(
|
await fact_storage.handle_document_tracking(
|
||||||
conn, bank_id, actual_doc_id, combined_content,
|
conn,
|
||||||
is_first_batch, retain_params, merged_tags,
|
bank_id,
|
||||||
|
actual_doc_id,
|
||||||
|
combined_content,
|
||||||
|
is_first_batch,
|
||||||
|
retain_params,
|
||||||
|
merged_tags,
|
||||||
)
|
)
|
||||||
document_ids_added.append(actual_doc_id)
|
document_ids_added.append(actual_doc_id)
|
||||||
|
|
||||||
|
|
@ -382,8 +416,15 @@ async def retain_batch(
|
||||||
|
|
||||||
# Insert facts and create all links (shared pipeline)
|
# Insert facts and create all links (shared pipeline)
|
||||||
result_unit_ids = await _insert_facts_and_links(
|
result_unit_ids = await _insert_facts_and_links(
|
||||||
conn, entity_resolver, bank_id, contents, extracted_facts,
|
conn,
|
||||||
processed_facts, config, log_buffer, outbox_callback,
|
entity_resolver,
|
||||||
|
bank_id,
|
||||||
|
contents,
|
||||||
|
extracted_facts,
|
||||||
|
processed_facts,
|
||||||
|
config,
|
||||||
|
log_buffer,
|
||||||
|
outbox_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
await entity_resolver.flush_pending_stats()
|
await entity_resolver.flush_pending_stats()
|
||||||
|
|
@ -406,9 +447,24 @@ async def retain_batch(
|
||||||
|
|
||||||
|
|
||||||
async def _try_delta_retain(
|
async def _try_delta_retain(
|
||||||
pool, embeddings_model, llm_config, entity_resolver, format_date_fn,
|
pool,
|
||||||
bank_id, contents_dicts, contents, config, document_id, fact_type_override,
|
embeddings_model,
|
||||||
document_tags, agent_name, log_buffer, start_time, operation_id, schema, outbox_callback,
|
llm_config,
|
||||||
|
entity_resolver,
|
||||||
|
format_date_fn,
|
||||||
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
config,
|
||||||
|
document_id,
|
||||||
|
fact_type_override,
|
||||||
|
document_tags,
|
||||||
|
agent_name,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
|
operation_id,
|
||||||
|
schema,
|
||||||
|
outbox_callback,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Attempt delta retain for a document upsert. Returns result tuple if delta
|
Attempt delta retain for a document upsert. Returns result tuple if delta
|
||||||
|
|
@ -472,8 +528,15 @@ async def _try_delta_retain(
|
||||||
# Nothing changed — just update document metadata/tags
|
# Nothing changed — just update document metadata/tags
|
||||||
log_buffer.append("[delta] No chunk changes detected — updating document metadata only")
|
log_buffer.append("[delta] No chunk changes detected — updating document metadata only")
|
||||||
return await _delta_metadata_only(
|
return await _delta_metadata_only(
|
||||||
pool, bank_id, contents_dicts, contents, effective_doc_id,
|
pool,
|
||||||
document_tags, log_buffer, start_time, outbox_callback,
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
effective_doc_id,
|
||||||
|
document_tags,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
|
outbox_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Build content items for only the changed/new chunks
|
# Build content items for only the changed/new chunks
|
||||||
|
|
@ -481,14 +544,30 @@ async def _try_delta_retain(
|
||||||
|
|
||||||
if not delta_contents:
|
if not delta_contents:
|
||||||
return await _delta_metadata_only(
|
return await _delta_metadata_only(
|
||||||
pool, bank_id, contents_dicts, contents, effective_doc_id,
|
pool,
|
||||||
document_tags, log_buffer, start_time, outbox_callback,
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
effective_doc_id,
|
||||||
|
document_tags,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
|
outbox_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extract facts and generate embeddings (shared pipeline)
|
# Extract facts and generate embeddings (shared pipeline)
|
||||||
extracted_facts, processed_facts, new_chunk_metadata, usage = await _extract_and_embed(
|
extracted_facts, processed_facts, new_chunk_metadata, usage = await _extract_and_embed(
|
||||||
delta_contents, llm_config, agent_name, config, embeddings_model, format_date_fn,
|
delta_contents,
|
||||||
fact_type_override, log_buffer, pool, operation_id, schema,
|
llm_config,
|
||||||
|
agent_name,
|
||||||
|
config,
|
||||||
|
embeddings_model,
|
||||||
|
format_date_fn,
|
||||||
|
fact_type_override,
|
||||||
|
log_buffer,
|
||||||
|
pool,
|
||||||
|
operation_id,
|
||||||
|
schema,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Database transaction
|
# Database transaction
|
||||||
|
|
@ -510,7 +589,12 @@ async def _try_delta_retain(
|
||||||
combined_content = "\n".join([c.get("content", "") for c in contents_dicts])
|
combined_content = "\n".join([c.get("content", "") for c in contents_dicts])
|
||||||
retain_params, merged_tags = _build_retain_params(contents_dicts, document_tags)
|
retain_params, merged_tags = _build_retain_params(contents_dicts, document_tags)
|
||||||
await fact_storage.upsert_document_metadata(
|
await fact_storage.upsert_document_metadata(
|
||||||
conn, bank_id, effective_doc_id, combined_content, retain_params, merged_tags,
|
conn,
|
||||||
|
bank_id,
|
||||||
|
effective_doc_id,
|
||||||
|
combined_content,
|
||||||
|
retain_params,
|
||||||
|
merged_tags,
|
||||||
)
|
)
|
||||||
log_buffer.append(f" Document metadata update in {time.time() - step_start:.3f}s")
|
log_buffer.append(f" Document metadata update in {time.time() - step_start:.3f}s")
|
||||||
|
|
||||||
|
|
@ -570,8 +654,15 @@ async def _try_delta_retain(
|
||||||
|
|
||||||
# Insert facts and create all links (shared pipeline)
|
# Insert facts and create all links (shared pipeline)
|
||||||
result_unit_ids = await _insert_facts_and_links(
|
result_unit_ids = await _insert_facts_and_links(
|
||||||
conn, entity_resolver, bank_id, contents, extracted_facts,
|
conn,
|
||||||
processed_facts, config, log_buffer, outbox_callback,
|
entity_resolver,
|
||||||
|
bank_id,
|
||||||
|
contents,
|
||||||
|
extracted_facts,
|
||||||
|
processed_facts,
|
||||||
|
config,
|
||||||
|
log_buffer,
|
||||||
|
outbox_callback,
|
||||||
)
|
)
|
||||||
|
|
||||||
await entity_resolver.flush_pending_stats()
|
await entity_resolver.flush_pending_stats()
|
||||||
|
|
@ -591,8 +682,15 @@ async def _try_delta_retain(
|
||||||
|
|
||||||
|
|
||||||
async def _delta_metadata_only(
|
async def _delta_metadata_only(
|
||||||
pool, bank_id, contents_dicts, contents, document_id, document_tags,
|
pool,
|
||||||
log_buffer, start_time, outbox_callback,
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
document_id,
|
||||||
|
document_tags,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
|
outbox_callback,
|
||||||
):
|
):
|
||||||
"""Handle the case where no chunks changed — just update document metadata and tags."""
|
"""Handle the case where no chunks changed — just update document metadata and tags."""
|
||||||
async with acquire_with_retry(pool) as conn:
|
async with acquire_with_retry(pool) as conn:
|
||||||
|
|
@ -600,7 +698,12 @@ async def _delta_metadata_only(
|
||||||
combined_content = "\n".join([c.get("content", "") for c in contents_dicts])
|
combined_content = "\n".join([c.get("content", "") for c in contents_dicts])
|
||||||
retain_params, merged_tags = _build_retain_params(contents_dicts, document_tags)
|
retain_params, merged_tags = _build_retain_params(contents_dicts, document_tags)
|
||||||
await fact_storage.upsert_document_metadata(
|
await fact_storage.upsert_document_metadata(
|
||||||
conn, bank_id, document_id, combined_content, retain_params, merged_tags,
|
conn,
|
||||||
|
bank_id,
|
||||||
|
document_id,
|
||||||
|
combined_content,
|
||||||
|
retain_params,
|
||||||
|
merged_tags,
|
||||||
)
|
)
|
||||||
await fact_storage.update_memory_units_tags(conn, bank_id, document_id, merged_tags)
|
await fact_storage.update_memory_units_tags(conn, bank_id, document_id, merged_tags)
|
||||||
if outbox_callback:
|
if outbox_callback:
|
||||||
|
|
@ -645,8 +748,17 @@ def _build_contents(contents_dicts: list[RetainContentDict], document_tags: list
|
||||||
|
|
||||||
|
|
||||||
async def _handle_zero_facts_documents(
|
async def _handle_zero_facts_documents(
|
||||||
pool, bank_id, contents_dicts, contents, config, document_id,
|
pool,
|
||||||
is_first_batch, document_tags, chunks, log_buffer, start_time,
|
bank_id,
|
||||||
|
contents_dicts,
|
||||||
|
contents,
|
||||||
|
config,
|
||||||
|
document_id,
|
||||||
|
is_first_batch,
|
||||||
|
document_tags,
|
||||||
|
chunks,
|
||||||
|
log_buffer,
|
||||||
|
start_time,
|
||||||
):
|
):
|
||||||
"""Handle document tracking when zero facts were extracted."""
|
"""Handle document tracking when zero facts were extracted."""
|
||||||
docs_tracked = 0
|
docs_tracked = 0
|
||||||
|
|
@ -677,8 +789,13 @@ async def _handle_zero_facts_documents(
|
||||||
contents_dicts, document_tags, doc_contents=doc_contents
|
contents_dicts, document_tags, doc_contents=doc_contents
|
||||||
)
|
)
|
||||||
await fact_storage.handle_document_tracking(
|
await fact_storage.handle_document_tracking(
|
||||||
conn, bank_id, actual_doc_id, combined_content,
|
conn,
|
||||||
is_first_batch, retain_params, merged_tags,
|
bank_id,
|
||||||
|
actual_doc_id,
|
||||||
|
combined_content,
|
||||||
|
is_first_batch,
|
||||||
|
retain_params,
|
||||||
|
merged_tags,
|
||||||
)
|
)
|
||||||
docs_tracked += 1
|
docs_tracked += 1
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,24 @@
|
||||||
"""
|
"""
|
||||||
Hindsight Client - Clean, pythonic wrapper for the Hindsight API.
|
Hindsight Client - Clean, pythonic wrapper for the Hindsight API.
|
||||||
|
|
||||||
This package provides a high-level interface for common Hindsight operations.
|
This package provides a high-level ``Hindsight`` class with simplified methods
|
||||||
For advanced use cases, use the auto-generated API client directly.
|
for the most common operations (retain, recall, reflect, banks, mental models,
|
||||||
|
directives).
|
||||||
|
|
||||||
|
For operations not available as convenience methods — such as documents,
|
||||||
|
entities, async operations, webhooks, and monitoring — use the low-level API
|
||||||
|
clients exposed as properties on the ``Hindsight`` instance (e.g.
|
||||||
|
``client.documents``, ``client.entities``, ``client.operations``).
|
||||||
|
All low-level methods are async.
|
||||||
|
|
||||||
|
Quick start::
|
||||||
|
|
||||||
Example:
|
|
||||||
```python
|
|
||||||
from hindsight_client import Hindsight
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
client = Hindsight(base_url="http://localhost:8888")
|
client = Hindsight(base_url="http://localhost:8888")
|
||||||
|
|
||||||
# Store a memory
|
# Store a memory
|
||||||
result = client.retain(bank_id="alice", content="Alice loves AI")
|
client.retain(bank_id="alice", content="Alice loves AI")
|
||||||
print(result.success)
|
|
||||||
|
|
||||||
# Search memories
|
# Search memories
|
||||||
response = client.recall(bank_id="alice", query="What does Alice like?")
|
response = client.recall(bank_id="alice", query="What does Alice like?")
|
||||||
|
|
@ -22,7 +28,19 @@ Example:
|
||||||
# Generate contextual answer
|
# Generate contextual answer
|
||||||
answer = client.reflect(bank_id="alice", query="What are my interests?")
|
answer = client.reflect(bank_id="alice", query="What are my interests?")
|
||||||
print(answer.text)
|
print(answer.text)
|
||||||
```
|
|
||||||
|
Low-level API access::
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
|
||||||
|
# List documents
|
||||||
|
docs = asyncio.run(client.documents.list_documents("alice"))
|
||||||
|
|
||||||
|
# Check operation status
|
||||||
|
status = asyncio.run(client.operations.get_operation_status("alice", "op-id"))
|
||||||
|
|
||||||
|
# List entities
|
||||||
|
entities = asyncio.run(client.entities.list_entities("alice"))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from hindsight_client_api.models.bank_profile_response import BankProfileResponse
|
from hindsight_client_api.models.bank_profile_response import BankProfileResponse
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,18 @@ from pathlib import Path
|
||||||
from typing import Any, Literal
|
from typing import Any, Literal
|
||||||
|
|
||||||
import hindsight_client_api
|
import hindsight_client_api
|
||||||
from hindsight_client_api.api import banks_api, directives_api, files_api, memory_api, mental_models_api
|
from hindsight_client_api.api import (
|
||||||
|
banks_api,
|
||||||
|
directives_api,
|
||||||
|
documents_api,
|
||||||
|
entities_api,
|
||||||
|
files_api,
|
||||||
|
memory_api,
|
||||||
|
mental_models_api,
|
||||||
|
monitoring_api,
|
||||||
|
operations_api,
|
||||||
|
webhooks_api,
|
||||||
|
)
|
||||||
from hindsight_client_api.models import (
|
from hindsight_client_api.models import (
|
||||||
memory_item,
|
memory_item,
|
||||||
recall_request,
|
recall_request,
|
||||||
|
|
@ -44,27 +55,68 @@ class Hindsight:
|
||||||
"""
|
"""
|
||||||
High-level, easy-to-use Hindsight API client.
|
High-level, easy-to-use Hindsight API client.
|
||||||
|
|
||||||
Example:
|
This class provides simplified methods for the most common operations:
|
||||||
```python
|
retain, recall, reflect, bank management, mental models, and directives.
|
||||||
|
|
||||||
|
**Async vs sync:** Every convenience method has an async counterpart
|
||||||
|
prefixed with ``a`` (e.g. ``aretain``, ``arecall``, ``areflect``).
|
||||||
|
**Prefer the async variants** (``aretain``, ``arecall``, ``areflect``, etc.)
|
||||||
|
whenever you are inside an async context (``async def``, event loops,
|
||||||
|
frameworks like FastAPI/LangGraph/CrewAI). The sync versions (``retain``,
|
||||||
|
``recall``, ``reflect``) are convenience wrappers that call
|
||||||
|
``asyncio.run_until_complete`` under the hood — they exist for scripts and
|
||||||
|
REPLs but will raise errors if an event loop is already running.
|
||||||
|
|
||||||
|
For operations not covered here (documents, entities, operations/async jobs,
|
||||||
|
webhooks, file uploads, monitoring), use the low-level API clients exposed
|
||||||
|
as properties on this class. These are auto-generated from the OpenAPI spec
|
||||||
|
and cover the full API surface. **All low-level methods are async-only.**
|
||||||
|
|
||||||
|
Example — async (preferred)::
|
||||||
|
|
||||||
from hindsight_client import Hindsight
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
# Without authentication
|
|
||||||
client = Hindsight(base_url="http://localhost:8888")
|
|
||||||
|
|
||||||
# With API key authentication
|
|
||||||
client = Hindsight(base_url="http://localhost:8888", api_key="your-api-key")
|
client = Hindsight(base_url="http://localhost:8888", api_key="your-api-key")
|
||||||
|
|
||||||
# Store a memory
|
# Inside an async function — use the a* methods
|
||||||
|
await client.aretain(bank_id="alice", content="Alice loves AI")
|
||||||
|
response = await client.arecall(bank_id="alice", query="What does Alice like?")
|
||||||
|
answer = await client.areflect(bank_id="alice", query="What are my interests?")
|
||||||
|
|
||||||
|
Example — sync (scripts / REPLs only)::
|
||||||
|
|
||||||
|
# Outside an async context — sync wrappers are available
|
||||||
client.retain(bank_id="alice", content="Alice loves AI")
|
client.retain(bank_id="alice", content="Alice loves AI")
|
||||||
|
|
||||||
# Recall memories
|
|
||||||
response = client.recall(bank_id="alice", query="What does Alice like?")
|
response = client.recall(bank_id="alice", query="What does Alice like?")
|
||||||
for r in response.results:
|
|
||||||
print(r.text)
|
|
||||||
|
|
||||||
# Generate contextual answer
|
Example — low-level API for advanced operations::
|
||||||
answer = client.reflect(bank_id="alice", query="What are my interests?")
|
|
||||||
```
|
# Access documents, entities, operations, webhooks, etc.
|
||||||
|
# All low-level methods are async-only — use 'await' or asyncio.run().
|
||||||
|
|
||||||
|
# List documents in a bank
|
||||||
|
docs = await client.documents.list_documents("alice")
|
||||||
|
|
||||||
|
# Delete a specific document
|
||||||
|
await client.documents.delete_document("alice", "doc-123")
|
||||||
|
|
||||||
|
# Check async operation status
|
||||||
|
status = await client.operations.get_operation_status("alice", "op-456")
|
||||||
|
|
||||||
|
# List entities
|
||||||
|
entities = await client.entities.list_entities("alice")
|
||||||
|
|
||||||
|
Available low-level API properties:
|
||||||
|
- ``client.memory``: Core memory operations (MemoryApi)
|
||||||
|
- ``client.banks``: Bank management (BanksApi)
|
||||||
|
- ``client.documents``: Document CRUD (DocumentsApi)
|
||||||
|
- ``client.entities``: Entity browsing (EntitiesApi)
|
||||||
|
- ``client.mental_models``: Mental model management (MentalModelsApi)
|
||||||
|
- ``client.directives``: Directive management (DirectivesApi)
|
||||||
|
- ``client.operations``: Async operation tracking (OperationsApi)
|
||||||
|
- ``client.webhooks``: Webhook management (WebhooksApi)
|
||||||
|
- ``client.files``: File upload (FilesApi)
|
||||||
|
- ``client.monitoring``: Health/version checks (MonitoringApi)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, base_url: str, api_key: str | None = None, timeout: float = 300.0):
|
def __init__(self, base_url: str, api_key: str | None = None, timeout: float = 300.0):
|
||||||
|
|
@ -88,6 +140,66 @@ class Hindsight:
|
||||||
self._mental_models_api = mental_models_api.MentalModelsApi(self._api_client)
|
self._mental_models_api = mental_models_api.MentalModelsApi(self._api_client)
|
||||||
self._directives_api = directives_api.DirectivesApi(self._api_client)
|
self._directives_api = directives_api.DirectivesApi(self._api_client)
|
||||||
self._files_api = files_api.FilesApi(self._api_client)
|
self._files_api = files_api.FilesApi(self._api_client)
|
||||||
|
self._documents_api = documents_api.DocumentsApi(self._api_client)
|
||||||
|
self._entities_api = entities_api.EntitiesApi(self._api_client)
|
||||||
|
self._operations_api = operations_api.OperationsApi(self._api_client)
|
||||||
|
self._webhooks_api = webhooks_api.WebhooksApi(self._api_client)
|
||||||
|
self._monitoring_api = monitoring_api.MonitoringApi(self._api_client)
|
||||||
|
|
||||||
|
# -- Low-level API accessors ------------------------------------------------
|
||||||
|
# These expose the full, auto-generated API surface for operations not
|
||||||
|
# covered by the convenience methods above. All methods on these objects
|
||||||
|
# are async — use ``await`` or ``asyncio.run()`` to call them.
|
||||||
|
|
||||||
|
@property
|
||||||
|
def memory(self) -> memory_api.MemoryApi:
|
||||||
|
"""Low-level Memory API — retain, recall, reflect, list/clear memories, tags, and graph."""
|
||||||
|
return self._memory_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def banks(self) -> banks_api.BanksApi:
|
||||||
|
"""Low-level Banks API — create, update, delete banks; stats; consolidation; config."""
|
||||||
|
return self._banks_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def documents(self) -> documents_api.DocumentsApi:
|
||||||
|
"""Low-level Documents API — list, get, update, delete documents and chunks."""
|
||||||
|
return self._documents_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entities(self) -> entities_api.EntitiesApi:
|
||||||
|
"""Low-level Entities API — list, get, and regenerate entity observations."""
|
||||||
|
return self._entities_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mental_models(self) -> mental_models_api.MentalModelsApi:
|
||||||
|
"""Low-level Mental Models API — create, list, get, update, refresh, delete, history."""
|
||||||
|
return self._mental_models_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def directives(self) -> directives_api.DirectivesApi:
|
||||||
|
"""Low-level Directives API — create, list, get, update, delete."""
|
||||||
|
return self._directives_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def operations(self) -> operations_api.OperationsApi:
|
||||||
|
"""Low-level Operations API — get status, list, cancel, retry async operations."""
|
||||||
|
return self._operations_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def webhooks(self) -> webhooks_api.WebhooksApi:
|
||||||
|
"""Low-level Webhooks API — create, list, update, delete webhooks and deliveries."""
|
||||||
|
return self._webhooks_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def files(self) -> files_api.FilesApi:
|
||||||
|
"""Low-level Files API — upload and retain files."""
|
||||||
|
return self._files_api
|
||||||
|
|
||||||
|
@property
|
||||||
|
def monitoring(self) -> monitoring_api.MonitoringApi:
|
||||||
|
"""Low-level Monitoring API — health check, version, metrics."""
|
||||||
|
return self._monitoring_api
|
||||||
|
|
||||||
def __enter__(self):
|
def __enter__(self):
|
||||||
"""Context manager entry."""
|
"""Context manager entry."""
|
||||||
|
|
@ -128,7 +240,7 @@ class Hindsight:
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
) -> RetainResponse:
|
) -> RetainResponse:
|
||||||
"""
|
"""
|
||||||
Store a single memory (simplified interface).
|
Store a single memory (sync wrapper — prefer :meth:`aretain` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -167,11 +279,13 @@ class Hindsight:
|
||||||
retain_async: bool = False,
|
retain_async: bool = False,
|
||||||
) -> RetainResponse:
|
) -> RetainResponse:
|
||||||
"""
|
"""
|
||||||
Store multiple memories in batch.
|
Store multiple memories in batch (sync wrapper — prefer :meth:`aretain_batch` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags'
|
items: List of memory items, each a dict with 'content' (required) and optional keys:
|
||||||
|
'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags',
|
||||||
|
'observation_scopes' (str or list[list[str]]), 'strategy'.
|
||||||
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
||||||
document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
|
document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
|
||||||
retain_async: If True, process asynchronously in background (default: False)
|
retain_async: If True, process asynchronously in background (default: False)
|
||||||
|
|
@ -179,37 +293,16 @@ class Hindsight:
|
||||||
Returns:
|
Returns:
|
||||||
RetainResponse with success status and item count
|
RetainResponse with success status and item count
|
||||||
"""
|
"""
|
||||||
from hindsight_client_api.models.entity_input import EntityInput
|
return _run_async(
|
||||||
from hindsight_client_api.models.timestamp import Timestamp
|
self.aretain_batch(
|
||||||
|
bank_id=bank_id,
|
||||||
memory_items = []
|
items=items,
|
||||||
for item in items:
|
document_id=document_id,
|
||||||
entities = None
|
document_tags=document_tags,
|
||||||
if item.get("entities"):
|
retain_async=retain_async,
|
||||||
entities = [EntityInput(text=e["text"], type=e.get("type")) for e in item["entities"]]
|
|
||||||
raw_ts = item.get("timestamp")
|
|
||||||
timestamp_val = Timestamp(actual_instance=raw_ts) if raw_ts is not None else None
|
|
||||||
memory_items.append(
|
|
||||||
memory_item.MemoryItem(
|
|
||||||
content=item["content"],
|
|
||||||
timestamp=timestamp_val,
|
|
||||||
context=item.get("context"),
|
|
||||||
metadata=item.get("metadata"),
|
|
||||||
# Use item's document_id if provided, otherwise fall back to batch-level document_id
|
|
||||||
document_id=item.get("document_id") or document_id,
|
|
||||||
entities=entities,
|
|
||||||
tags=item.get("tags"),
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
request_obj = retain_request.RetainRequest(
|
|
||||||
items=memory_items,
|
|
||||||
var_async=retain_async,
|
|
||||||
document_tags=document_tags,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
return _run_async(self._memory_api.retain_memories(bank_id, request_obj, _request_timeout=self._timeout))
|
|
||||||
|
|
||||||
def retain_files(
|
def retain_files(
|
||||||
self,
|
self,
|
||||||
bank_id: str,
|
bank_id: str,
|
||||||
|
|
@ -218,7 +311,7 @@ class Hindsight:
|
||||||
files_metadata: list[dict[str, Any]] | None = None,
|
files_metadata: list[dict[str, Any]] | None = None,
|
||||||
) -> FileRetainResponse:
|
) -> FileRetainResponse:
|
||||||
"""
|
"""
|
||||||
Upload files and retain their contents as memories.
|
Upload files and retain their contents as memories (sync wrapper).
|
||||||
|
|
||||||
Files are automatically converted to text (PDF, DOCX, images via OCR, audio via
|
Files are automatically converted to text (PDF, DOCX, images via OCR, audio via
|
||||||
transcription, and more) and ingested as memories. Processing is always asynchronous
|
transcription, and more) and ingested as memories. Processing is always asynchronous
|
||||||
|
|
@ -262,9 +355,10 @@ class Hindsight:
|
||||||
max_source_facts_tokens: int = 4096,
|
max_source_facts_tokens: int = 4096,
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
||||||
|
tag_groups: list[dict[str, Any]] | None = None,
|
||||||
) -> RecallResponse:
|
) -> RecallResponse:
|
||||||
"""
|
"""
|
||||||
Recall memories using semantic similarity.
|
Recall memories using semantic similarity (sync wrapper — prefer :meth:`arecall` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -283,41 +377,32 @@ class Hindsight:
|
||||||
tags: Optional list of tags to filter memories by
|
tags: Optional list of tags to filter memories by
|
||||||
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
||||||
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
||||||
|
tag_groups: Optional list of tag group filters for advanced boolean tag matching.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
RecallResponse with results, optional entities, optional chunks, optional source_facts, and optional trace
|
RecallResponse with results, optional entities, optional chunks, optional source_facts, and optional trace
|
||||||
"""
|
"""
|
||||||
from hindsight_client_api.models import (
|
return _run_async(
|
||||||
chunk_include_options,
|
self.arecall(
|
||||||
entity_include_options,
|
bank_id=bank_id,
|
||||||
include_options,
|
query=query,
|
||||||
source_facts_include_options,
|
types=types,
|
||||||
|
max_tokens=max_tokens,
|
||||||
|
budget=budget,
|
||||||
|
trace=trace,
|
||||||
|
query_timestamp=query_timestamp,
|
||||||
|
include_entities=include_entities,
|
||||||
|
max_entity_tokens=max_entity_tokens,
|
||||||
|
include_chunks=include_chunks,
|
||||||
|
max_chunk_tokens=max_chunk_tokens,
|
||||||
|
include_source_facts=include_source_facts,
|
||||||
|
max_source_facts_tokens=max_source_facts_tokens,
|
||||||
|
tags=tags,
|
||||||
|
tags_match=tags_match,
|
||||||
|
tag_groups=tag_groups,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
include_opts = include_options.IncludeOptions(
|
|
||||||
entities=entity_include_options.EntityIncludeOptions(max_tokens=max_entity_tokens)
|
|
||||||
if include_entities
|
|
||||||
else None,
|
|
||||||
chunks=chunk_include_options.ChunkIncludeOptions(max_tokens=max_chunk_tokens) if include_chunks else None,
|
|
||||||
source_facts=source_facts_include_options.SourceFactsIncludeOptions(max_tokens=max_source_facts_tokens)
|
|
||||||
if include_source_facts
|
|
||||||
else None,
|
|
||||||
)
|
|
||||||
|
|
||||||
request_obj = recall_request.RecallRequest(
|
|
||||||
query=query,
|
|
||||||
types=types,
|
|
||||||
budget=budget,
|
|
||||||
max_tokens=max_tokens,
|
|
||||||
trace=trace,
|
|
||||||
query_timestamp=query_timestamp,
|
|
||||||
include=include_opts,
|
|
||||||
tags=tags,
|
|
||||||
tags_match=tags_match,
|
|
||||||
)
|
|
||||||
|
|
||||||
return _run_async(self._memory_api.recall_memories(bank_id, request_obj, _request_timeout=self._timeout))
|
|
||||||
|
|
||||||
def reflect(
|
def reflect(
|
||||||
self,
|
self,
|
||||||
bank_id: str,
|
bank_id: str,
|
||||||
|
|
@ -329,9 +414,13 @@ class Hindsight:
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
||||||
include_facts: bool = False,
|
include_facts: bool = False,
|
||||||
|
tag_groups: list[dict[str, Any]] | None = None,
|
||||||
|
fact_types: list[str] | None = None,
|
||||||
|
exclude_mental_models: bool = False,
|
||||||
|
exclude_mental_model_ids: list[str] | None = None,
|
||||||
) -> ReflectResponse:
|
) -> ReflectResponse:
|
||||||
"""
|
"""
|
||||||
Generate a contextual answer based on bank identity and memories.
|
Generate a contextual answer based on bank identity and memories (sync wrapper — prefer :meth:`areflect` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -347,25 +436,33 @@ class Hindsight:
|
||||||
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
||||||
include_facts: If True, the response will include a 'based_on' field listing
|
include_facts: If True, the response will include a 'based_on' field listing
|
||||||
the memories, mental models, and directives used to construct the answer.
|
the memories, mental models, and directives used to construct the answer.
|
||||||
|
tag_groups: Optional list of tag group filters for advanced boolean tag matching.
|
||||||
|
fact_types: Optional list of fact types to include (world, experience, observation).
|
||||||
|
exclude_mental_models: If True, exclude all mental models from reflection (default: False).
|
||||||
|
exclude_mental_model_ids: Optional list of specific mental model IDs to exclude.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ReflectResponse with answer text, optionally facts used, and optionally
|
ReflectResponse with answer text, optionally facts used, and optionally
|
||||||
structured_output if response_schema was provided
|
structured_output if response_schema was provided
|
||||||
"""
|
"""
|
||||||
include = ReflectIncludeOptions(facts={}) if include_facts else None
|
return _run_async(
|
||||||
request_obj = reflect_request.ReflectRequest(
|
self.areflect(
|
||||||
query=query,
|
bank_id=bank_id,
|
||||||
budget=budget,
|
query=query,
|
||||||
context=context,
|
budget=budget,
|
||||||
max_tokens=max_tokens,
|
context=context,
|
||||||
response_schema=response_schema,
|
max_tokens=max_tokens,
|
||||||
tags=tags,
|
response_schema=response_schema,
|
||||||
tags_match=tags_match,
|
tags=tags,
|
||||||
include=include,
|
tags_match=tags_match,
|
||||||
|
include_facts=include_facts,
|
||||||
|
tag_groups=tag_groups,
|
||||||
|
fact_types=fact_types,
|
||||||
|
exclude_mental_models=exclude_mental_models,
|
||||||
|
exclude_mental_model_ids=exclude_mental_model_ids,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
return _run_async(self._memory_api.reflect(bank_id, request_obj, _request_timeout=self._timeout))
|
|
||||||
|
|
||||||
def list_memories(
|
def list_memories(
|
||||||
self,
|
self,
|
||||||
bank_id: str,
|
bank_id: str,
|
||||||
|
|
@ -374,7 +471,7 @@ class Hindsight:
|
||||||
limit: int = 100,
|
limit: int = 100,
|
||||||
offset: int = 0,
|
offset: int = 0,
|
||||||
) -> ListMemoryUnitsResponse:
|
) -> ListMemoryUnitsResponse:
|
||||||
"""List memory units with pagination."""
|
"""List memory units with pagination (sync wrapper — use ``await client.memory.list_memories(...)`` in async code)."""
|
||||||
return _run_async(
|
return _run_async(
|
||||||
self._memory_api.list_memories(
|
self._memory_api.list_memories(
|
||||||
bank_id=bank_id,
|
bank_id=bank_id,
|
||||||
|
|
@ -402,8 +499,9 @@ class Hindsight:
|
||||||
enable_observations: bool | None = None,
|
enable_observations: bool | None = None,
|
||||||
observations_mission: str | None = None,
|
observations_mission: str | None = None,
|
||||||
reflect_mission: str | None = None,
|
reflect_mission: str | None = None,
|
||||||
|
background: str | None = None,
|
||||||
) -> BankProfileResponse:
|
) -> BankProfileResponse:
|
||||||
"""Create or update a memory bank.
|
"""Create or update a memory bank (sync wrapper — prefer :meth:`acreate_bank` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: Unique identifier for the bank
|
bank_id: Unique identifier for the bank
|
||||||
|
|
@ -420,6 +518,7 @@ class Hindsight:
|
||||||
enable_observations: Toggle automatic observation consolidation after retain().
|
enable_observations: Toggle automatic observation consolidation after retain().
|
||||||
observations_mission: Controls what gets synthesised into observations. Replaces built-in rules.
|
observations_mission: Controls what gets synthesised into observations. Replaces built-in rules.
|
||||||
reflect_mission: Mission/context for Reflect operations.
|
reflect_mission: Mission/context for Reflect operations.
|
||||||
|
background: Optional background context for the bank.
|
||||||
"""
|
"""
|
||||||
return _run_async(
|
return _run_async(
|
||||||
self._acreate_bank(
|
self._acreate_bank(
|
||||||
|
|
@ -437,6 +536,7 @@ class Hindsight:
|
||||||
retain_chunk_size=retain_chunk_size,
|
retain_chunk_size=retain_chunk_size,
|
||||||
enable_observations=enable_observations,
|
enable_observations=enable_observations,
|
||||||
observations_mission=observations_mission,
|
observations_mission=observations_mission,
|
||||||
|
background=background,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -456,6 +556,7 @@ class Hindsight:
|
||||||
retain_chunk_size: int | None = None,
|
retain_chunk_size: int | None = None,
|
||||||
enable_observations: bool | None = None,
|
enable_observations: bool | None = None,
|
||||||
observations_mission: str | None = None,
|
observations_mission: str | None = None,
|
||||||
|
background: str | None = None,
|
||||||
) -> BankProfileResponse:
|
) -> BankProfileResponse:
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
|
|
@ -466,6 +567,8 @@ class Hindsight:
|
||||||
body["mission"] = mission
|
body["mission"] = mission
|
||||||
if reflect_mission is not None:
|
if reflect_mission is not None:
|
||||||
body["reflect_mission"] = reflect_mission
|
body["reflect_mission"] = reflect_mission
|
||||||
|
if background is not None:
|
||||||
|
body["background"] = background
|
||||||
# Individual disposition fields take priority over legacy disposition dict
|
# Individual disposition fields take priority over legacy disposition dict
|
||||||
if disposition_skepticism is not None:
|
if disposition_skepticism is not None:
|
||||||
body["disposition_skepticism"] = disposition_skepticism
|
body["disposition_skepticism"] = disposition_skepticism
|
||||||
|
|
@ -528,8 +631,9 @@ class Hindsight:
|
||||||
enable_observations: bool | None = None,
|
enable_observations: bool | None = None,
|
||||||
observations_mission: str | None = None,
|
observations_mission: str | None = None,
|
||||||
reflect_mission: str | None = None,
|
reflect_mission: str | None = None,
|
||||||
|
background: str | None = None,
|
||||||
) -> BankProfileResponse:
|
) -> BankProfileResponse:
|
||||||
"""Create or update a memory bank (async).
|
"""Create or update a memory bank (async — preferred over :meth:`create_bank`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: Unique identifier for the bank
|
bank_id: Unique identifier for the bank
|
||||||
|
|
@ -546,6 +650,7 @@ class Hindsight:
|
||||||
enable_observations: Toggle automatic observation consolidation after retain().
|
enable_observations: Toggle automatic observation consolidation after retain().
|
||||||
observations_mission: Controls what gets synthesised into observations. Replaces built-in rules.
|
observations_mission: Controls what gets synthesised into observations. Replaces built-in rules.
|
||||||
reflect_mission: Mission/context for Reflect operations.
|
reflect_mission: Mission/context for Reflect operations.
|
||||||
|
background: Optional background context for the bank.
|
||||||
"""
|
"""
|
||||||
return await self._acreate_bank(
|
return await self._acreate_bank(
|
||||||
bank_id,
|
bank_id,
|
||||||
|
|
@ -562,6 +667,7 @@ class Hindsight:
|
||||||
retain_chunk_size=retain_chunk_size,
|
retain_chunk_size=retain_chunk_size,
|
||||||
enable_observations=enable_observations,
|
enable_observations=enable_observations,
|
||||||
observations_mission=observations_mission,
|
observations_mission=observations_mission,
|
||||||
|
background=background,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def aset_mission(self, bank_id: str, mission: str) -> dict[str, Any]:
|
async def aset_mission(self, bank_id: str, mission: str) -> dict[str, Any]:
|
||||||
|
|
@ -581,11 +687,13 @@ class Hindsight:
|
||||||
retain_async: bool = False,
|
retain_async: bool = False,
|
||||||
) -> RetainResponse:
|
) -> RetainResponse:
|
||||||
"""
|
"""
|
||||||
Store multiple memories in batch (async).
|
Store multiple memories in batch (async — preferred over :meth:`retain_batch`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags'
|
items: List of memory items, each a dict with 'content' (required) and optional keys:
|
||||||
|
'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags',
|
||||||
|
'observation_scopes' (str or list[list[str]]), 'strategy'.
|
||||||
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
||||||
document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
|
document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
|
||||||
retain_async: If True, process asynchronously in background (default: False)
|
retain_async: If True, process asynchronously in background (default: False)
|
||||||
|
|
@ -594,6 +702,7 @@ class Hindsight:
|
||||||
RetainResponse with success status and item count
|
RetainResponse with success status and item count
|
||||||
"""
|
"""
|
||||||
from hindsight_client_api.models.entity_input import EntityInput
|
from hindsight_client_api.models.entity_input import EntityInput
|
||||||
|
from hindsight_client_api.models.observation_scopes import ObservationScopes
|
||||||
from hindsight_client_api.models.timestamp import Timestamp
|
from hindsight_client_api.models.timestamp import Timestamp
|
||||||
|
|
||||||
memory_items = []
|
memory_items = []
|
||||||
|
|
@ -603,6 +712,9 @@ class Hindsight:
|
||||||
entities = [EntityInput(text=e["text"], type=e.get("type")) for e in item["entities"]]
|
entities = [EntityInput(text=e["text"], type=e.get("type")) for e in item["entities"]]
|
||||||
raw_ts = item.get("timestamp")
|
raw_ts = item.get("timestamp")
|
||||||
timestamp_val = Timestamp(actual_instance=raw_ts) if raw_ts is not None else None
|
timestamp_val = Timestamp(actual_instance=raw_ts) if raw_ts is not None else None
|
||||||
|
obs_scopes = None
|
||||||
|
if item.get("observation_scopes") is not None:
|
||||||
|
obs_scopes = ObservationScopes(actual_instance=item["observation_scopes"])
|
||||||
memory_items.append(
|
memory_items.append(
|
||||||
memory_item.MemoryItem(
|
memory_item.MemoryItem(
|
||||||
content=item["content"],
|
content=item["content"],
|
||||||
|
|
@ -613,6 +725,8 @@ class Hindsight:
|
||||||
document_id=item.get("document_id") or document_id,
|
document_id=item.get("document_id") or document_id,
|
||||||
entities=entities,
|
entities=entities,
|
||||||
tags=item.get("tags"),
|
tags=item.get("tags"),
|
||||||
|
observation_scopes=obs_scopes,
|
||||||
|
strategy=item.get("strategy"),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -636,7 +750,7 @@ class Hindsight:
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
) -> RetainResponse:
|
) -> RetainResponse:
|
||||||
"""
|
"""
|
||||||
Store a single memory (async).
|
Store a single memory (async — preferred over :meth:`retain`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -683,9 +797,10 @@ class Hindsight:
|
||||||
max_source_facts_tokens: int = 4096,
|
max_source_facts_tokens: int = 4096,
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
||||||
|
tag_groups: list[dict[str, Any]] | None = None,
|
||||||
) -> RecallResponse:
|
) -> RecallResponse:
|
||||||
"""
|
"""
|
||||||
Recall memories using semantic similarity (async).
|
Recall memories using semantic similarity (async — preferred over :meth:`recall`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -704,6 +819,11 @@ class Hindsight:
|
||||||
tags: Optional list of tags to filter memories by
|
tags: Optional list of tags to filter memories by
|
||||||
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
||||||
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
||||||
|
tag_groups: Optional list of tag group filters for advanced boolean tag matching.
|
||||||
|
Each element is a dict representing a tag group node (TagGroupLeaf, TagGroupAnd,
|
||||||
|
TagGroupOr, or TagGroupNot). Example::
|
||||||
|
|
||||||
|
[{"tags": ["customer"], "match": "all"}, {"not": {"tags": ["internal"]}}]
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
RecallResponse with results, optional entities, optional chunks, optional source_facts, and optional trace
|
RecallResponse with results, optional entities, optional chunks, optional source_facts, and optional trace
|
||||||
|
|
@ -725,6 +845,12 @@ class Hindsight:
|
||||||
else None,
|
else None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
tag_groups_objs = None
|
||||||
|
if tag_groups is not None:
|
||||||
|
from hindsight_client_api.models.recall_request_tag_groups_inner import RecallRequestTagGroupsInner
|
||||||
|
|
||||||
|
tag_groups_objs = [RecallRequestTagGroupsInner.from_dict(tg) for tg in tag_groups]
|
||||||
|
|
||||||
request_obj = recall_request.RecallRequest(
|
request_obj = recall_request.RecallRequest(
|
||||||
query=query,
|
query=query,
|
||||||
types=types,
|
types=types,
|
||||||
|
|
@ -735,6 +861,7 @@ class Hindsight:
|
||||||
include=include_opts,
|
include=include_opts,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
tags_match=tags_match,
|
tags_match=tags_match,
|
||||||
|
tag_groups=tag_groups_objs,
|
||||||
)
|
)
|
||||||
|
|
||||||
return await self._memory_api.recall_memories(bank_id, request_obj, _request_timeout=self._timeout)
|
return await self._memory_api.recall_memories(bank_id, request_obj, _request_timeout=self._timeout)
|
||||||
|
|
@ -749,9 +876,14 @@ class Hindsight:
|
||||||
response_schema: dict[str, Any] | None = None,
|
response_schema: dict[str, Any] | None = None,
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
|
||||||
|
include_facts: bool = False,
|
||||||
|
tag_groups: list[dict[str, Any]] | None = None,
|
||||||
|
fact_types: list[str] | None = None,
|
||||||
|
exclude_mental_models: bool = False,
|
||||||
|
exclude_mental_model_ids: list[str] | None = None,
|
||||||
) -> ReflectResponse:
|
) -> ReflectResponse:
|
||||||
"""
|
"""
|
||||||
Generate a contextual answer based on bank identity and memories (async).
|
Generate a contextual answer based on bank identity and memories (async — preferred over :meth:`reflect`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -765,11 +897,25 @@ class Hindsight:
|
||||||
tags: Optional list of tags to filter memories by
|
tags: Optional list of tags to filter memories by
|
||||||
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
|
||||||
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
"any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
|
||||||
|
include_facts: If True, the response will include a 'based_on' field listing
|
||||||
|
the memories, mental models, and directives used to construct the answer.
|
||||||
|
tag_groups: Optional list of tag group filters for advanced boolean tag matching.
|
||||||
|
fact_types: Optional list of fact types to include (world, experience, observation).
|
||||||
|
exclude_mental_models: If True, exclude all mental models from reflection (default: False).
|
||||||
|
exclude_mental_model_ids: Optional list of specific mental model IDs to exclude.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
ReflectResponse with answer text, optionally facts used, and optionally
|
ReflectResponse with answer text, optionally facts used, and optionally
|
||||||
structured_output if response_schema was provided
|
structured_output if response_schema was provided
|
||||||
"""
|
"""
|
||||||
|
include = ReflectIncludeOptions(facts={}) if include_facts else None
|
||||||
|
|
||||||
|
tag_groups_objs = None
|
||||||
|
if tag_groups is not None:
|
||||||
|
from hindsight_client_api.models.recall_request_tag_groups_inner import RecallRequestTagGroupsInner
|
||||||
|
|
||||||
|
tag_groups_objs = [RecallRequestTagGroupsInner.from_dict(tg) for tg in tag_groups]
|
||||||
|
|
||||||
request_obj = reflect_request.ReflectRequest(
|
request_obj = reflect_request.ReflectRequest(
|
||||||
query=query,
|
query=query,
|
||||||
budget=budget,
|
budget=budget,
|
||||||
|
|
@ -778,6 +924,11 @@ class Hindsight:
|
||||||
response_schema=response_schema,
|
response_schema=response_schema,
|
||||||
tags=tags,
|
tags=tags,
|
||||||
tags_match=tags_match,
|
tags_match=tags_match,
|
||||||
|
include=include,
|
||||||
|
tag_groups=tag_groups_objs,
|
||||||
|
fact_types=fact_types,
|
||||||
|
exclude_mental_models=exclude_mental_models or None,
|
||||||
|
exclude_mental_model_ids=exclude_mental_model_ids,
|
||||||
)
|
)
|
||||||
|
|
||||||
return await self._memory_api.reflect(bank_id, request_obj, _request_timeout=self._timeout)
|
return await self._memory_api.reflect(bank_id, request_obj, _request_timeout=self._timeout)
|
||||||
|
|
@ -795,7 +946,7 @@ class Hindsight:
|
||||||
id: str | None = None,
|
id: str | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Create a mental model (runs reflect in background).
|
Create a mental model (sync wrapper — use ``await client.mental_models.create_mental_model(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -828,7 +979,7 @@ class Hindsight:
|
||||||
|
|
||||||
def list_mental_models(self, bank_id: str, tags: list[str] | None = None):
|
def list_mental_models(self, bank_id: str, tags: list[str] | None = None):
|
||||||
"""
|
"""
|
||||||
List all mental models in a bank.
|
List all mental models in a bank (sync wrapper — use ``await client.mental_models.list_mental_models(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -841,7 +992,7 @@ class Hindsight:
|
||||||
|
|
||||||
def get_mental_model(self, bank_id: str, mental_model_id: str):
|
def get_mental_model(self, bank_id: str, mental_model_id: str):
|
||||||
"""
|
"""
|
||||||
Get a specific mental model.
|
Get a specific mental model (sync wrapper — use ``await client.mental_models.get_mental_model(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -854,7 +1005,7 @@ class Hindsight:
|
||||||
|
|
||||||
def refresh_mental_model(self, bank_id: str, mental_model_id: str):
|
def refresh_mental_model(self, bank_id: str, mental_model_id: str):
|
||||||
"""
|
"""
|
||||||
Refresh a mental model to update with current knowledge.
|
Refresh a mental model (sync wrapper — use ``await client.mental_models.refresh_mental_model(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -876,7 +1027,7 @@ class Hindsight:
|
||||||
trigger: dict[str, Any] | None = None,
|
trigger: dict[str, Any] | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Update a mental model's metadata.
|
Update a mental model's metadata (sync wrapper — use ``await client.mental_models.update_mental_model(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -908,7 +1059,7 @@ class Hindsight:
|
||||||
|
|
||||||
def delete_mental_model(self, bank_id: str, mental_model_id: str):
|
def delete_mental_model(self, bank_id: str, mental_model_id: str):
|
||||||
"""
|
"""
|
||||||
Delete a mental model.
|
Delete a mental model (sync wrapper — use ``await client.mental_models.delete_mental_model(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -918,7 +1069,7 @@ class Hindsight:
|
||||||
|
|
||||||
def get_mental_model_history(self, bank_id: str, mental_model_id: str):
|
def get_mental_model_history(self, bank_id: str, mental_model_id: str):
|
||||||
"""
|
"""
|
||||||
Get the content change history of a mental model.
|
Get the content change history of a mental model (sync wrapper — use ``await client.mental_models.get_mental_model_history(...)`` in async code).
|
||||||
|
|
||||||
Returns a list of history entries (most recent first), each with
|
Returns a list of history entries (most recent first), each with
|
||||||
``previous_content`` and ``changed_at`` fields.
|
``previous_content`` and ``changed_at`` fields.
|
||||||
|
|
@ -941,7 +1092,7 @@ class Hindsight:
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Create a directive (hard rule for reflect).
|
Create a directive (sync wrapper — use ``await client.directives.create_directive(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -968,7 +1119,7 @@ class Hindsight:
|
||||||
|
|
||||||
def list_directives(self, bank_id: str, tags: list[str] | None = None):
|
def list_directives(self, bank_id: str, tags: list[str] | None = None):
|
||||||
"""
|
"""
|
||||||
List all directives in a bank.
|
List all directives in a bank (sync wrapper — use ``await client.directives.list_directives(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -981,7 +1132,7 @@ class Hindsight:
|
||||||
|
|
||||||
def get_directive(self, bank_id: str, directive_id: str):
|
def get_directive(self, bank_id: str, directive_id: str):
|
||||||
"""
|
"""
|
||||||
Get a specific directive.
|
Get a specific directive (sync wrapper — use ``await client.directives.get_directive(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -1003,7 +1154,7 @@ class Hindsight:
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Update a directive.
|
Update a directive (sync wrapper — use ``await client.directives.update_directive(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -1031,7 +1182,7 @@ class Hindsight:
|
||||||
|
|
||||||
def delete_directive(self, bank_id: str, directive_id: str):
|
def delete_directive(self, bank_id: str, directive_id: str):
|
||||||
"""
|
"""
|
||||||
Delete a directive.
|
Delete a directive (sync wrapper — use ``await client.directives.delete_directive(...)`` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -1041,7 +1192,7 @@ class Hindsight:
|
||||||
|
|
||||||
def get_bank_config(self, bank_id: str) -> dict[str, Any]:
|
def get_bank_config(self, bank_id: str) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Get the resolved configuration for a bank, including any bank-level overrides.
|
Get the resolved configuration for a bank (sync wrapper — use ``await client.banks.get_bank_config(...)`` in async code).
|
||||||
|
|
||||||
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
||||||
|
|
||||||
|
|
@ -1079,7 +1230,7 @@ class Hindsight:
|
||||||
disposition_empathy: int | None = None,
|
disposition_empathy: int | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Update configuration overrides for a bank.
|
Update configuration overrides for a bank (sync wrapper — use ``await client.banks.update_bank_config(...)`` in async code).
|
||||||
|
|
||||||
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
||||||
|
|
||||||
|
|
@ -1131,7 +1282,7 @@ class Hindsight:
|
||||||
|
|
||||||
def reset_bank_config(self, bank_id: str) -> dict[str, Any]:
|
def reset_bank_config(self, bank_id: str) -> dict[str, Any]:
|
||||||
"""
|
"""
|
||||||
Reset all bank-level configuration overrides, reverting to server defaults.
|
Reset all bank-level config overrides (sync wrapper — use ``await client.banks.reset_bank_config(...)`` in async code).
|
||||||
|
|
||||||
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
Can be disabled on the server by setting ``HINDSIGHT_API_ENABLE_BANK_CONFIG_API=false``.
|
||||||
|
|
||||||
|
|
@ -1155,7 +1306,7 @@ class Hindsight:
|
||||||
|
|
||||||
def delete_bank(self, bank_id: str):
|
def delete_bank(self, bank_id: str):
|
||||||
"""
|
"""
|
||||||
Delete a memory bank.
|
Delete a memory bank (sync wrapper — prefer :meth:`adelete_bank` in async code).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
@ -1164,7 +1315,7 @@ class Hindsight:
|
||||||
|
|
||||||
async def adelete_bank(self, bank_id: str):
|
async def adelete_bank(self, bank_id: str):
|
||||||
"""
|
"""
|
||||||
Delete a memory bank (async).
|
Delete a memory bank (async — preferred over :meth:`delete_bank`).
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
bank_id: The memory bank ID
|
bank_id: The memory bank ID
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue