* feat(skill): validate links, strip images, include openapi.json and changelog - Add post-processing step to rewrite Docusaurus site-root paths (e.g. /developer/foo) to proper relative .md paths within the skill - Strip markdown and HTML images from all generated files since assets are not bundled with the skill - Copy hindsight-docs/static/openapi.json into references/openapi.json and map /api-reference links to it - Include changelog.md from src/pages/ alongside faq and best-practices - Add final validation step that fails the build if any link still points outside the skill directory * ci: run generate-docs-skill in verify-generated-files job * fix(skill): strip unresolvable site-root links instead of leaving them broken * fix(skill): write file when images stripped but no links rewritten * chore(skill): regenerate with fixed links, stripped images, changelog and openapi * fix(skill): handle changelog as directory, add agno/hermes integrations, rebase on main
7.2 KiB
Main Methods
Hindsight provides three core operations: retain, recall, and reflect.
{/* Import raw source files */}
💡 Prerequisites
Make sure you've installed Hindsight and completed the Quick Start.
Retain: Store Information
Store conversations, documents, and facts into a memory bank.
Python
# Store a single fact
client.retain(
bank_id="my-bank",
content="Alice joined Google in March 2024 as a Senior ML Engineer"
)
# Store a conversation
conversation = """
User: What did you work on today?
Assistant: I reviewed the new ML pipeline architecture.
User: How did it look?
Assistant: Promising, but needs better error handling.
"""
client.retain(
bank_id="my-bank",
content=conversation,
context="Daily standup conversation"
)
# Batch retain multiple items
client.retain_batch(
bank_id="my-bank",
items=[
{"content": "Bob prefers Python for data science"},
{"content": "Alice recommends using pytest for testing"},
{"content": "The team uses GitHub for code reviews"}
]
)
Node.js
// Store a single fact
await client.retain('my-bank', 'Alice joined Google in March 2024 as a Senior ML Engineer');
// Store a conversation
const conversation = `
User: What did you work on today?
Assistant: I reviewed the new ML pipeline architecture.
User: How did it look?
Assistant: Promising, but needs better error handling.
`;
await client.retain('my-bank', conversation, {
context: 'Daily standup conversation'
});
// Batch retain multiple items
await client.retainBatch('my-bank', [
{ content: 'Bob prefers Python for data science' },
{ content: 'Alice recommends using pytest for testing' },
{ content: 'The team uses GitHub for code reviews' }
]);
CLI
# Store a single fact
hindsight memory retain my-bank "Alice joined Google in March 2024 as a Senior ML Engineer"
# Store from a file
hindsight memory retain-files my-bank conversation.txt --context "Daily standup"
# Store multiple files
hindsight memory retain-files my-bank docs/
Go
# Section 'main-retain' not found in api/main-methods.go
What happens: Content is processed by an LLM to extract rich facts, identify entities, and build connections in a knowledge graph.
See: Retain Details for advanced options and parameters.
Recall: Search Memories
Search for relevant memories using multi-strategy retrieval.
Python
# Basic search
results = client.recall(
bank_id="my-bank",
query="What does Alice do at Google?"
)
for result in results.results:
print(f"- {result.text}")
# Search with options
results = client.recall(
bank_id="my-bank",
query="What happened last spring?",
budget="high", # More thorough graph traversal
max_tokens=8192, # Return more context
types=["world"] # Only world facts
)
# Include source chunks for more context
results = client.recall(
bank_id="my-bank",
query="Tell me about Alice",
include_chunks=True,
max_chunk_tokens=500
)
# Check chunk details (chunks are on response level, keyed by memory ID)
for result in results.results:
print(f"Memory: {result.text}")
if results.chunks and result.id in results.chunks:
chunk = results.chunks[result.id]
print(f" Source: {chunk.text[:100]}...")
Node.js
// Basic search
const results = await client.recall('my-bank', 'What does Alice do at Google?');
for (const result of results.results) {
console.log(`- ${result.text}`);
}
// Search with options
const filteredResults = await client.recall('my-bank', 'What happened last spring?', {
budget: 'high',
maxTokens: 8192,
types: ['world']
});
// Include entity information
const entityResults = await client.recall('my-bank', 'Tell me about Alice', {
includeEntities: true,
maxEntityTokens: 500
});
// Check entity details
for (const [entityId, entity] of Object.entries(entityResults.entities || {})) {
console.log(`Entity: ${entity.canonical_name}`);
console.log(`Observations: ${entity.observations}`);
}
CLI
# Basic search
hindsight memory recall my-bank "What does Alice do at Google?"
# Search with options
hindsight memory recall my-bank "What happened last spring?" \
--budget high \
--max-tokens 8192 \
--fact-type world,experience
# Verbose output
hindsight memory recall my-bank "Tell me about Alice" -v
Go
# Section 'main-recall' not found in api/main-methods.go
What happens: Four search strategies (semantic, keyword, graph, temporal) run in parallel, results are fused and reranked.
See: Recall Details for tuning quality vs latency.
Reflect: Reason with Disposition
Generate disposition-aware responses using memories and observations.
Python
# Basic reflect
response = client.reflect(
bank_id="my-bank",
query="Should we adopt TypeScript for our backend?",
include_facts=True,
)
print(response.text)
print("\nBased on:", len(response.based_on.memories if response.based_on else []), "facts")
# Reflect with options
response = client.reflect(
bank_id="my-bank",
query="What are Alice's strengths for the team lead role?",
budget="high", # More thorough reasoning
include_facts=True,
)
# See which facts influenced the response
for fact in (response.based_on.memories if response.based_on else []):
print(f"- {fact.text}")
Node.js
// Basic reflect
const response = await client.reflect('my-bank', 'Should we adopt TypeScript for our backend?');
console.log(response.text);
console.log('\nBased on:', (response.based_on || []).length, 'facts');
// Reflect with options
const detailedResponse = await client.reflect('my-bank', "What are Alice's strengths for the team lead role?", {
budget: 'high'
});
// See which facts influenced the response
for (const fact of detailedResponse.based_on || []) {
console.log(`- ${fact.text}`);
}
CLI
# Basic reflect
hindsight memory reflect my-bank "Should we adopt TypeScript for our backend?"
# With higher reasoning budget
hindsight memory reflect my-bank "Analyze our tech stack" --budget high
Go
# Section 'main-reflect' not found in api/main-methods.go
What happens: Memories and observations are recalled, bank disposition is applied, and the LLM reasons through the evidence to generate a response.
See: Reflect Details for disposition configuration.
Comparison
| Feature | Retain | Recall | Reflect |
|---|---|---|---|
| Purpose | Store information | Find information | Reason about information |
| Input | Raw text/documents | Search query | Question/prompt |
| Output | Memory IDs | Ranked facts + observations | Reasoned response |
| Uses LLM | Yes (extraction) | No | Yes (generation) |
| Uses observations | No | Yes | Yes |
| Disposition | No | No | Yes |
Next Steps
- Retain — Advanced options for storing memories
- Recall — Tuning search quality and performance
- Reflect — Configuring disposition
- Memory Banks — Managing memory bank disposition