Skip to main content

Retain: Storing Memories

The Retain operation stores new information in a memory bank. Hindsight processes the content, extracts structured memories, and indexes them for efficient retrieval.

Overview​

Retain is the primary way to add information to Hindsight:

  • Process natural language content
  • Extract and categorize memories automatically
  • Store world facts, experience, and observations
  • Build a searchable knowledge base indexed for TEMPR retrieval

Basic Usage​

from hindsight_client import Hindsight

client = Hindsight(
base_url="https://api.hindsight.vectorize.io",
api_key="your-api-key"
)

# Simple retain
client.retain(
bank_id="your-bank-id",
content="The user's favorite color is blue and they work as a software engineer."
)

How It Works​

When you call Retain:

  1. Content Analysis - Hindsight processes your text using AI
  2. Memory Extraction - Individual memories are identified
  3. Categorization - Each memory is classified by type:
    • World Facts (objective facts from external sources)
    • Experience (events and interactions)
    • Observations (automatically synthesized knowledge consolidated from facts)
  4. Indexing - Memories are indexed for TEMPR retrieval (semantic, keyword, graph, temporal)
  5. Storage - Data is persisted in the memory bank

Request Parameters​

ParameterTypeRequiredDescription
bank_idstringYesTarget memory bank ID (in URL path)
itemsarrayYesArray of memory items to store
items[].contentstringYesText content to process
items[].contextstringNoContext about the content
items[].timestampstringNoISO 8601 timestamp for the memory
asyncbooleanNoProcess asynchronously (default: false)

Response​

{
"success": true,
"bank_id": "my-assistant",
"items_count": 1,
"async": false,
"operation_id": null,
"usage": {
"input_tokens": 2684,
"output_tokens": 511,
"total_tokens": 3195
}
}
FieldDescription
successWhether the operation succeeded
bank_idThe memory bank ID
items_countNumber of items processed
asyncWhether processed asynchronously
operation_idID for tracking async operations
usageToken consumption breakdown

Content Best Practices​

Be Specific​

client.retain(
bank_id=bank_id,
content="Alice prefers Python over JavaScript for backend development. She has 5 years of experience with FastAPI."
)

Include Context​

client.retain(
bank_id=bank_id,
content="During our March 15 meeting, the client mentioned they need the report by April 1st and prefer PDF format."
)

Use Natural Language​

client.retain(
bank_id=bank_id,
content="The customer is based in Tokyo, Japan and operates in the financial services sector. They typically respond faster to emails than phone calls."
)

Batch Operations​

contents = [
"User completed onboarding on January 10th.",
"User's team has 5 members.",
"User prefers weekly check-ins over daily standups."
]

for content in contents:
client.retain(bank_id=bank_id, content=content)

With Metadata​

client.retain(
bank_id=bank_id,
content="Meeting notes from Q1 review...",
source="meeting_transcript",
metadata={
"meeting_date": "2024-03-15",
"attendees": ["alice", "bob", "charlie"]
}
)

Memory Types Explained​

Hindsight automatically categorizes memories into four types:

World Facts​

Objective facts received from external sources:

  • "Paris is the capital of France"
  • "The project uses PostgreSQL for the database"
  • "The company was founded in 2020"
  • "The user's email is alice@example.com"

Experience​

Events and interactions that have occurred:

  • "User signed up for the premium plan last week"
  • "We had a productive call with the design team"
  • "The deployment completed successfully at 2 PM"
  • "I sent a welcome email on January 10th"

Observations​

Automatically synthesized knowledge — new facts are analyzed and consolidated into observations with evidence tracking. Observations are created and refined automatically in the background after each retain call:

  • "User is growing comfortable with async Python"
  • "Traffic peaks on Tuesday mornings"
  • "Support tickets decrease after documentation updates"

Mental Model Auto-Refresh​

When memories are stored via Retain, Hindsight consolidates new facts into observations. Mental models that have trigger.refresh_after_consolidation enabled will be automatically refreshed after this consolidation completes, keeping them up to date with the latest knowledge. See Mental Models for more details.

Each refresh is a billable Refresh Model call ($0.05), one per model rebuilt, so how a model keeps itself fresh is a cost decision as much as a freshness one. Knowledge base pages are mental models, which is what makes this worth reading before you build on it: a bank whose pages are broadly scoped, under steady retains, can spend more on Refresh Model than on every other operation combined.

Choosing how a model stays fresh​

A model refreshes in one of three ways. refresh_after_consolidation and refresh_cron are mutually exclusive — a model follows one or the other, never both.

modesetwhen it rebuildscost
Manualneither fieldonly when you askexactly what you ask for
On consolidationtrigger.refresh_after_consolidation: trueafter consolidations that touched its scopescales with how much you write
Scheduledtrigger.refresh_cron: "0 * * * *"on the schedule, only if something changedcapped by the schedule

The default depends on how the model was created: a mental model you create through the API, an MCP tool or the dashboard is manual, while a knowledge base page is created on consolidation, so that a page keeps itself current without being asked.

A schedule is the better choice for most pages. It gives the model a ceiling you pick — an hourly cron is at most 24 rebuilds a day — and a tick whose scope saw no new memories is skipped rather than rebuilt, so a quiet bank costs nothing. Refreshing on consolidation has no such ceiling: it follows your write volume, so the same page costs more in a busy week than a slow one, for reasons that have nothing to do with the page.

Use refresh_after_consolidation when a model genuinely has to reflect the last retain — a live operational summary, say — and accept that its cost tracks your ingestion rate.

Cron expressions are standard 5-field UTC, so 0 3 * * * is daily at 03:00 UTC.

Neither automatic mode rebuilds blindly. A model is refreshed only if new memories actually landed in its scope since it last read them; models the consolidation or tick could not have affected are skipped and not billed. The number of calls therefore tracks how broadly your models are scoped, not simply how many you have.

How often an automatic refresh can run​

Both automatic modes are rate-limited. On Hindsight Cloud a model rebuilds at most once a minute: a trigger arriving sooner is not dropped but queued, and every further trigger in that window folds into the one queued rebuild. So a burst of retains costs one refresh rather than one per retain.

Two things the limit does not apply to:

  • Explicit refreshes. Refreshing from the API, an MCP tool or the dashboard ignores the floor entirely, so you can always bring a page current on demand.
  • Models that opt out. trigger.min_refresh_interval_seconds on an individual model overrides the default — including 0, which restores rebuilding on every trigger for a model that has to be immediate.

Raise it on a model that does not need to be current to the minute: trigger.min_refresh_interval_seconds: 3600 rebuilds it at most hourly, however much you write.

Token Usage​

Retain operations consume tokens based on:

  • Input content length
  • Processing complexity
  • Number of memories extracted

Monitor usage on the Usage Analytics page.

Error Handling​

try:
client.retain(bank_id=bank_id, content=content)
print("Memory stored successfully")
except Exception as e:
print(f"Error: {e}")

Common Errors​

ErrorCauseSolution
401 UnauthorizedInvalid API keyCheck your API key
402 Payment RequiredInsufficient creditsAdd credits to your account
404 Not FoundInvalid bank_idVerify the bank exists
400 Bad RequestEmpty contentProvide non-empty content