#!/usr/bin/env python3 """ Recall API examples for Hindsight. Run: python examples/api/recall.py """ import os import requests HINDSIGHT_URL = os.getenv("HINDSIGHT_API_URL", "http://localhost:8888") # ============================================================================= # Setup (not shown in docs) # ============================================================================= from hindsight_client import Hindsight client = Hindsight(base_url=HINDSIGHT_URL) # Seed some data for recall examples client.retain(bank_id="my-bank", content="Alice works at Google as a software engineer") client.retain(bank_id="my-bank", content="Alice loves hiking on weekends") client.retain(bank_id="my-bank", content="Bob is a data scientist who works with Alice") # ============================================================================= # Doc Examples # ============================================================================= # [docs:recall-basic] response = client.recall(bank_id="my-bank", query="What does Alice do?") # response.results is a list of RecallResult objects, each with: # - id: fact ID # - text: the extracted fact # - type: "world", "experience", or "observation" # - context: context label set during retain # - metadata: dict[str, str] set during retain # - tags: list of tags # - entities: list of entity name strings linked to this fact # - occurred_start: ISO datetime of when the event started # - occurred_end: ISO datetime of when the event ended # - mentioned_at: ISO datetime of when the fact was retained # - document_id: document this fact belongs to # - chunk_id: chunk this fact was extracted from # Example response.results: # [ # RecallResult(id="a1b2...", text="Alice works at Google as a software engineer", type="world", context="career", ...), # RecallResult(id="c3d4...", text="Alice got promoted to senior engineer", type="experience", occurred_start="2024-03-15T00:00:00Z", ...), # ] # [/docs:recall-basic] # [docs:recall-with-options] response = client.recall( bank_id="my-bank", query="What does Alice do?", types=["world", "experience"], budget="high", max_tokens=8000, trace=True, ) # Access results for r in response.results: print(f"- {r.text}") # [/docs:recall-with-options] # [docs:recall-world-only] # Only world facts (objective information) world_facts = client.recall( bank_id="my-bank", query="Where does Alice work?", types=["world"] ) # [/docs:recall-world-only] # [docs:recall-experience-only] # Only experience (conversations and events) experience = client.recall( bank_id="my-bank", query="What have I recommended?", types=["experience"] ) # [/docs:recall-experience-only] # [docs:recall-observations-only] # Only observations (consolidated knowledge) observations = client.recall( bank_id="my-bank", query="What patterns have I learned?", types=["observation"] ) # [/docs:recall-observations-only] # [docs:recall-with-observations] # Include observations in recall results = client.recall( bank_id="my-bank", query="What programming languages does Alice prefer?", types=["world", "experience", "observation"] ) # Observations only observations = client.recall( bank_id="my-bank", query="What patterns have I learned?", types=["observation"] ) # [/docs:recall-with-observations] # [docs:recall-source-facts] # Recall observations and include their source facts response = client.recall( bank_id="my-bank", query="What patterns have I learned about Alice?", types=["observation"], include_source_facts=True, max_source_facts_tokens=4096, ) for obs in response.results: print(f"Observation: {obs.text}") if obs.source_fact_ids and response.source_facts: print(" Derived from:") for fact_id in obs.source_fact_ids: fact = response.source_facts.get(fact_id) if fact: print(f" - [{fact.type}] {fact.text}") # [/docs:recall-source-facts] # [docs:recall-token-budget] # Fill up to 4K tokens of context with relevant memories results = client.recall(bank_id="my-bank", query="What do I know about Alice?", max_tokens=4096) # Smaller budget for quick lookups results = client.recall(bank_id="my-bank", query="Alice's email", max_tokens=500) # [/docs:recall-token-budget] # [docs:recall-budget-levels] # Quick lookup results = client.recall(bank_id="my-bank", query="Alice's email", budget="low") # Deep exploration results = client.recall(bank_id="my-bank", query="How are Alice and Bob connected?", budget="high") # [/docs:recall-budget-levels] # [docs:recall-with-tags] # Filter recall to only memories tagged for a specific user response = client.recall( bank_id="my-bank", query="What feedback did the user give?", tags=["user:alice"], tags_match="any" # OR matching, includes untagged (default) ) # [/docs:recall-with-tags] # [docs:recall-tags-strict] # Strict mode: only return memories that have matching tags (exclude untagged) response = client.recall( bank_id="my-bank", query="What did the user say?", tags=["user:alice"], tags_match="any_strict" # OR matching, excludes untagged memories ) # [/docs:recall-tags-strict] # [docs:recall-tags-all] # AND matching: require ALL specified tags to be present response = client.recall( bank_id="my-bank", query="What bugs were reported?", tags=["user:alice", "bug-report"], tags_match="all_strict" # Memory must have BOTH tags ) # [/docs:recall-tags-all] # [docs:recall-tags-any] response = client.recall( bank_id="my-bank", query="communication preferences", tags=["user:alice"], tags_match="any", # default ) # Returns: # [match] "Alice prefers async communication" — has "user:alice" # [no match] "Bob dislikes long meetings" — no overlap with ["user:alice"] # [match] "Team uses Slack for announcements" — has "user:alice" # [match] "Company policy: no meetings on Fridays" — untagged, included by default # [/docs:recall-tags-any] # [docs:recall-tags-any-strict] response = client.recall( bank_id="my-bank", query="communication preferences", tags=["user:alice"], tags_match="any_strict", ) # Returns: # [match] "Alice prefers async communication" — has "user:alice" # [no match] "Bob dislikes long meetings" — no overlap with ["user:alice"] # [match] "Team uses Slack for announcements" — has "user:alice" # [no match] "Company policy: no meetings on Fridays" — untagged, excluded # [/docs:recall-tags-any-strict] # [docs:recall-tags-all-mode] response = client.recall( bank_id="my-bank", query="communication tools", tags=["user:alice", "team"], tags_match="all", ) # Returns: # [no match] "Alice prefers async communication" — missing "team" # [no match] "Bob dislikes long meetings" — missing both tags # [match] "Team uses Slack for announcements" — has both "user:alice" and "team" # [match] "Company policy: no meetings on Fridays" — untagged, included by default # [/docs:recall-tags-all-mode] # [docs:recall-tags-all-strict] response = client.recall( bank_id="my-bank", query="communication tools", tags=["user:alice", "team"], tags_match="all_strict", ) # Returns: # [no match] "Alice prefers async communication" — missing "team" # [no match] "Bob dislikes long meetings" — missing both tags # [match] "Team uses Slack for announcements" — has both "user:alice" and "team" # [no match] "Company policy: no meetings on Fridays" — untagged, excluded # [/docs:recall-tags-all-strict] # ============================================================================= # Legacy snippets for v0.3 docs (kept for backward compatibility) # ============================================================================= # [docs:recall-opinions-only] # Legacy: opinions replaced by observations in v0.4+ # Only retrieve opinions (beliefs and preferences) opinions = client.recall( bank_id="my-bank", query="What are my preferences?", types=["opinion"] ) # [/docs:recall-opinions-only] # [docs:recall-include-entities] # Legacy: entity summaries replaced by observations in v0.4+ # Include entity summaries in recall results response = client.recall( bank_id="my-bank", query="What do I know about Alice?", include_entities=True, max_entity_tokens=500 ) # [/docs:recall-include-entities] # ============================================================================= # Cleanup (not shown in docs) # ============================================================================= requests.delete(f"{HINDSIGHT_URL}/v1/default/banks/my-bank") print("recall.py: All examples passed")