fix docs on clients
This commit is contained in:
parent
ebc85a5c3d
commit
99db7b26c3
22 changed files with 372 additions and 476 deletions
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
|
|
@ -219,6 +219,9 @@ jobs:
|
||||||
|
|
||||||
release-helm-chart:
|
release-helm-chart:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
packages: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
@ -228,12 +231,18 @@ jobs:
|
||||||
with:
|
with:
|
||||||
version: 'latest'
|
version: 'latest'
|
||||||
|
|
||||||
|
- name: Log in to GHCR
|
||||||
|
run: echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io -u ${{ github.actor }} --password-stdin
|
||||||
|
|
||||||
- name: Lint Helm chart
|
- name: Lint Helm chart
|
||||||
run: helm lint helm/hindsight
|
run: helm lint helm/hindsight
|
||||||
|
|
||||||
- name: Package Helm chart
|
- name: Package Helm chart
|
||||||
run: helm package helm/hindsight --destination ./helm-packages
|
run: helm package helm/hindsight --destination ./helm-packages
|
||||||
|
|
||||||
|
- name: Push to GHCR OCI
|
||||||
|
run: helm push helm-packages/*.tgz oci://ghcr.io/${{ github.repository_owner }}/charts
|
||||||
|
|
||||||
- name: Upload artifacts
|
- name: Upload artifacts
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
24
README.md
24
README.md
|
|
@ -66,7 +66,7 @@ UI: http://localhost:9999
|
||||||
Install client:
|
Install client:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install hindsight-client
|
pip install hindsight-client -U
|
||||||
# or
|
# or
|
||||||
npm install @vectorize-io/hindsight-client
|
npm install @vectorize-io/hindsight-client
|
||||||
```
|
```
|
||||||
|
|
@ -91,7 +91,7 @@ client.reflect(bank_id="my-bank", query="Tell me about Alice")
|
||||||
### Python (embedded, no Docker)
|
### Python (embedded, no Docker)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pip install hindsight-all
|
pip install hindsight-all -U
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
|
@ -100,27 +100,27 @@ from hindsight import HindsightServer, HindsightClient
|
||||||
|
|
||||||
with HindsightServer(
|
with HindsightServer(
|
||||||
llm_provider="openai",
|
llm_provider="openai",
|
||||||
llm_model="gpt-4o-mini",
|
llm_model="gpt-5-mini",
|
||||||
llm_api_key=os.environ["OPENAI_API_KEY"]
|
llm_api_key=os.environ["OPENAI_API_KEY"]
|
||||||
) as server:
|
) as server:
|
||||||
client = HindsightClient(base_url=server.url)
|
client = HindsightClient(base_url=server.url)
|
||||||
client.retain(bank_id="my-agent", content="Alice works at Google")
|
client.retain(bank_id="my-bank", content="Alice works at Google")
|
||||||
results = client.recall(bank_id="my-agent", query="Where does Alice work?")
|
results = client.recall(bank_id="my-bank", query="Where does Alice work?")
|
||||||
```
|
```
|
||||||
|
|
||||||
### TypeScript
|
### Node.js / TypeScript
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install @vectorize-io/hindsight-client
|
npm install @vectorize-io/hindsight-client
|
||||||
```
|
```
|
||||||
|
|
||||||
```typescript
|
```javascript
|
||||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
const { HindsightClient } = require('@vectorize-io/hindsight-client');
|
||||||
|
|
||||||
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
||||||
|
|
||||||
await client.retain('my-agent', 'Alice loves hiking in Yosemite');
|
await client.retain('my-bank', 'Alice loves hiking in Yosemite');
|
||||||
const response = await client.recall('my-agent', 'What does Alice like?');
|
await client.recall('my-bank', 'What does Alice like?');
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -168,9 +168,7 @@ client = Hindsight(base_url="http://localhost:8888")
|
||||||
client.recall(bank_id="my-bank", query="What does Alice do?")
|
client.recall(bank_id="my-bank", query="What does Alice do?")
|
||||||
|
|
||||||
# Temporal
|
# Temporal
|
||||||
results = client.recall(bank_id="my-bank", query="What happened in June?")
|
client.recall(bank_id="my-bank", query="What happened in June?")
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Recall performs 4 retrieval strategies in parallel:
|
Recall performs 4 retrieval strategies in parallel:
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,7 @@ ENV HINDSIGHT_API_PORT=8888
|
||||||
ENV HINDSIGHT_API_LOG_LEVEL=info
|
ENV HINDSIGHT_API_LOG_LEVEL=info
|
||||||
ENV HINDSIGHT_ENABLE_API=true
|
ENV HINDSIGHT_ENABLE_API=true
|
||||||
ENV HINDSIGHT_ENABLE_CP=false
|
ENV HINDSIGHT_ENABLE_CP=false
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
CMD ["/app/start-all.sh"]
|
CMD ["/app/start-all.sh"]
|
||||||
|
|
||||||
|
|
@ -311,6 +312,7 @@ ENV NODE_ENV=production
|
||||||
ENV HINDSIGHT_CP_DATAPLANE_API_URL=http://localhost:8888
|
ENV HINDSIGHT_CP_DATAPLANE_API_URL=http://localhost:8888
|
||||||
ENV HINDSIGHT_ENABLE_API=true
|
ENV HINDSIGHT_ENABLE_API=true
|
||||||
ENV HINDSIGHT_ENABLE_CP=true
|
ENV HINDSIGHT_ENABLE_CP=true
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
CMD ["/app/start-all.sh"]
|
CMD ["/app/start-all.sh"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ PIDS=()
|
||||||
# Start API if enabled
|
# Start API if enabled
|
||||||
if [ "$ENABLE_API" = "true" ]; then
|
if [ "$ENABLE_API" = "true" ]; then
|
||||||
cd /app/api
|
cd /app/api
|
||||||
hindsight-api 2>&1 | sed 's/^/[api] /' &
|
hindsight-api 2>&1 | sed -u 's/^/[api] /' &
|
||||||
API_PID=$!
|
API_PID=$!
|
||||||
PIDS+=($API_PID)
|
PIDS+=($API_PID)
|
||||||
|
|
||||||
|
|
@ -42,7 +42,7 @@ fi
|
||||||
if [ "$ENABLE_CP" = "true" ]; then
|
if [ "$ENABLE_CP" = "true" ]; then
|
||||||
echo "🎛️ Starting Control Plane..."
|
echo "🎛️ Starting Control Plane..."
|
||||||
cd /app/control-plane
|
cd /app/control-plane
|
||||||
PORT=9999 node server.js 2>&1 | grep -v -E "^[[:space:]]*(▲|✓|-|$)" | sed 's/^/[control-plane] /' &
|
PORT=9999 node server.js 2>&1 | grep -v -E "^[[:space:]]*(▲|✓|-|$)" | sed -u 's/^/[control-plane] /' &
|
||||||
CP_PID=$!
|
CP_PID=$!
|
||||||
PIDS+=($CP_PID)
|
PIDS+=($CP_PID)
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -170,24 +170,38 @@ class LLMProvider:
|
||||||
"messages": messages,
|
"messages": messages,
|
||||||
}
|
}
|
||||||
|
|
||||||
if max_completion_tokens is not None:
|
|
||||||
call_params["max_completion_tokens"] = max_completion_tokens
|
|
||||||
# Check if model supports reasoning parameter (o1, o3, gpt-5 families)
|
# Check if model supports reasoning parameter (o1, o3, gpt-5 families)
|
||||||
model_lower = self.model.lower()
|
model_lower = self.model.lower()
|
||||||
is_reasoning_model = any(x in model_lower for x in ["gpt-5", "o1", "o3"])
|
is_reasoning_model = any(x in model_lower for x in ["gpt-5", "o1", "o3"])
|
||||||
|
|
||||||
|
# For GPT-4 and GPT-4.1 models, cap max_completion_tokens to 32000
|
||||||
|
is_gpt4_model = any(x in model_lower for x in ["gpt-4.1", "gpt-4-"])
|
||||||
|
if max_completion_tokens is not None:
|
||||||
|
if is_gpt4_model and max_completion_tokens > 32000:
|
||||||
|
max_completion_tokens = 32000
|
||||||
|
# For reasoning models, max_completion_tokens includes reasoning + output tokens
|
||||||
|
# Enforce minimum of 16000 to ensure enough space for both
|
||||||
|
if is_reasoning_model and max_completion_tokens < 16000:
|
||||||
|
max_completion_tokens = 16000
|
||||||
|
call_params["max_completion_tokens"] = max_completion_tokens
|
||||||
|
|
||||||
# GPT-5/o1/o3 family doesn't support custom temperature (only default 1)
|
# GPT-5/o1/o3 family doesn't support custom temperature (only default 1)
|
||||||
if temperature is not None and not is_reasoning_model:
|
if temperature is not None and not is_reasoning_model:
|
||||||
call_params["temperature"] = temperature
|
call_params["temperature"] = temperature
|
||||||
|
|
||||||
|
# Set reasoning_effort for reasoning models (OpenAI gpt-5, o1, o3)
|
||||||
|
if is_reasoning_model and self.provider == "openai":
|
||||||
|
call_params["reasoning_effort"] = self.reasoning_effort
|
||||||
|
|
||||||
# Provider-specific parameters
|
# Provider-specific parameters
|
||||||
if self.provider == "groq":
|
if self.provider == "groq":
|
||||||
call_params["seed"] = DEFAULT_LLM_SEED
|
call_params["seed"] = DEFAULT_LLM_SEED
|
||||||
call_params["extra_body"] = {
|
extra_body = {"service_tier": "auto"}
|
||||||
"service_tier": "auto",
|
# Only add reasoning parameters for reasoning models
|
||||||
"reasoning_effort": self.reasoning_effort,
|
if is_reasoning_model:
|
||||||
"include_reasoning": False,
|
extra_body["reasoning_effort"] = self.reasoning_effort
|
||||||
}
|
extra_body["include_reasoning"] = False
|
||||||
|
call_params["extra_body"] = extra_body
|
||||||
|
|
||||||
last_exception = None
|
last_exception = None
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,36 +10,30 @@ from hindsight_api.engine.llm_wrapper import LLMProvider
|
||||||
MODEL_MATRIX = [
|
MODEL_MATRIX = [
|
||||||
# OpenAI models
|
# OpenAI models
|
||||||
("openai", "gpt-4o-mini"),
|
("openai", "gpt-4o-mini"),
|
||||||
|
("openai", "gpt-4.1-mini"),
|
||||||
|
("openai", "gpt-4.1-nano"),
|
||||||
("openai", "gpt-5-mini"),
|
("openai", "gpt-5-mini"),
|
||||||
|
("openai", "gpt-5-nano"),
|
||||||
|
("openai", "gpt-5"),
|
||||||
# Groq models
|
# Groq models
|
||||||
("groq", "llama-3.3-70b-versatile"),
|
("groq", "llama-3.3-70b-versatile"),
|
||||||
("groq", "openai/gpt-oss-120b"),
|
("groq", "openai/gpt-oss-120b"),
|
||||||
|
("groq", "openai/gpt-oss-20b"),
|
||||||
# Gemini models
|
# Gemini models
|
||||||
("gemini", "gemini-2.0-flash"),
|
("gemini", "gemini-2.5-flash"),
|
||||||
("gemini", "gemini-2.5-flash-preview-05-20"),
|
("gemini", "gemini-2.5-flash-lite"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
def get_api_key_for_provider(provider: str) -> str | None:
|
def get_api_key_for_provider(provider: str) -> str | None:
|
||||||
"""Get API key for provider from environment variables."""
|
"""Get API key for provider from environment variables."""
|
||||||
# Try provider-specific env vars first
|
|
||||||
provider_key_map = {
|
provider_key_map = {
|
||||||
"openai": ["OPENAI_API_KEY", "HINDSIGHT_API_LLM_API_KEY"],
|
"openai": "OPENAI_API_KEY",
|
||||||
"groq": ["GROQ_API_KEY", "HINDSIGHT_API_LLM_API_KEY"],
|
"groq": "GROQ_API_KEY",
|
||||||
"gemini": ["GEMINI_API_KEY", "GOOGLE_API_KEY", "HINDSIGHT_API_LLM_API_KEY"],
|
"gemini": "GEMINI_API_KEY",
|
||||||
}
|
}
|
||||||
|
env_var = provider_key_map.get(provider)
|
||||||
for env_var in provider_key_map.get(provider, []):
|
return os.getenv(env_var) if env_var else None
|
||||||
key = os.getenv(env_var)
|
|
||||||
if key:
|
|
||||||
# For HINDSIGHT_API_LLM_API_KEY, only use if provider matches
|
|
||||||
if env_var == "HINDSIGHT_API_LLM_API_KEY":
|
|
||||||
configured_provider = os.getenv("HINDSIGHT_API_LLM_PROVIDER", "").lower()
|
|
||||||
if configured_provider == provider:
|
|
||||||
return key
|
|
||||||
else:
|
|
||||||
return key
|
|
||||||
return None
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("provider,model", MODEL_MATRIX)
|
@pytest.mark.parametrize("provider,model", MODEL_MATRIX)
|
||||||
|
|
@ -97,8 +91,10 @@ async def test_llm_provider_verify_connection(provider: str, model: str):
|
||||||
# Models that support large output (65000+ tokens)
|
# Models that support large output (65000+ tokens)
|
||||||
LARGE_OUTPUT_MODELS = [
|
LARGE_OUTPUT_MODELS = [
|
||||||
("openai", "gpt-5-mini"),
|
("openai", "gpt-5-mini"),
|
||||||
("gemini", "gemini-2.0-flash"),
|
("openai", "gpt-5-nano"),
|
||||||
("gemini", "gemini-2.5-flash-preview-05-20"),
|
("openai", "gpt-5"),
|
||||||
|
("gemini", "gemini-2.5-flash"),
|
||||||
|
("gemini", "gemini-2.5-flash-lite"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ Example:
|
||||||
print(result.success)
|
print(result.success)
|
||||||
|
|
||||||
# Search memories
|
# Search memories
|
||||||
results = client.recall(bank_id="alice", query="What does Alice like?")
|
response = client.recall(bank_id="alice", query="What does Alice like?")
|
||||||
for r in results:
|
for r in response.results:
|
||||||
print(r.text)
|
print(r.text)
|
||||||
|
|
||||||
# Generate contextual answer
|
# Generate contextual answer
|
||||||
|
|
@ -29,14 +29,59 @@ from .hindsight_client import Hindsight
|
||||||
|
|
||||||
# Re-export response types for convenient access
|
# Re-export response types for convenient access
|
||||||
from hindsight_client_api.models.retain_response import RetainResponse
|
from hindsight_client_api.models.retain_response import RetainResponse
|
||||||
from hindsight_client_api.models.recall_response import RecallResponse
|
from hindsight_client_api.models.recall_response import RecallResponse as _RecallResponse
|
||||||
from hindsight_client_api.models.recall_result import RecallResult
|
from hindsight_client_api.models.recall_result import RecallResult as _RecallResult
|
||||||
from hindsight_client_api.models.reflect_response import ReflectResponse
|
from hindsight_client_api.models.reflect_response import ReflectResponse
|
||||||
from hindsight_client_api.models.reflect_fact import ReflectFact
|
from hindsight_client_api.models.reflect_fact import ReflectFact
|
||||||
from hindsight_client_api.models.list_memory_units_response import ListMemoryUnitsResponse
|
from hindsight_client_api.models.list_memory_units_response import ListMemoryUnitsResponse
|
||||||
from hindsight_client_api.models.bank_profile_response import BankProfileResponse
|
from hindsight_client_api.models.bank_profile_response import BankProfileResponse
|
||||||
from hindsight_client_api.models.disposition_traits import DispositionTraits
|
from hindsight_client_api.models.disposition_traits import DispositionTraits
|
||||||
|
|
||||||
|
|
||||||
|
# Add cleaner __repr__ and __iter__ for REPL usability
|
||||||
|
def _recall_result_repr(self):
|
||||||
|
text_preview = self.text[:80] + "..." if len(self.text) > 80 else self.text
|
||||||
|
return f"RecallResult(id='{self.id[:8]}...', type='{self.type}', text='{text_preview}')"
|
||||||
|
|
||||||
|
|
||||||
|
def _recall_response_repr(self):
|
||||||
|
count = len(self.results) if self.results else 0
|
||||||
|
extras = []
|
||||||
|
if self.trace:
|
||||||
|
extras.append("trace=True")
|
||||||
|
if self.entities:
|
||||||
|
extras.append(f"entities={len(self.entities)}")
|
||||||
|
if self.chunks:
|
||||||
|
extras.append(f"chunks={len(self.chunks)}")
|
||||||
|
extras_str = ", " + ", ".join(extras) if extras else ""
|
||||||
|
return f"RecallResponse({count} results{extras_str})"
|
||||||
|
|
||||||
|
|
||||||
|
def _recall_response_iter(self):
|
||||||
|
"""Iterate directly over results for convenience."""
|
||||||
|
return iter(self.results or [])
|
||||||
|
|
||||||
|
|
||||||
|
def _recall_response_len(self):
|
||||||
|
"""Return number of results."""
|
||||||
|
return len(self.results) if self.results else 0
|
||||||
|
|
||||||
|
|
||||||
|
def _recall_response_getitem(self, index):
|
||||||
|
"""Access results by index."""
|
||||||
|
return self.results[index]
|
||||||
|
|
||||||
|
|
||||||
|
_RecallResult.__repr__ = _recall_result_repr
|
||||||
|
_RecallResponse.__repr__ = _recall_response_repr
|
||||||
|
_RecallResponse.__iter__ = _recall_response_iter
|
||||||
|
_RecallResponse.__len__ = _recall_response_len
|
||||||
|
_RecallResponse.__getitem__ = _recall_response_getitem
|
||||||
|
|
||||||
|
# Re-export with patched repr
|
||||||
|
RecallResult = _RecallResult
|
||||||
|
RecallResponse = _RecallResponse
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Hindsight",
|
"Hindsight",
|
||||||
# Response types
|
# Response types
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,9 @@ class Hindsight:
|
||||||
client.retain(bank_id="alice", content="Alice loves AI")
|
client.retain(bank_id="alice", content="Alice loves AI")
|
||||||
|
|
||||||
# Recall memories
|
# Recall memories
|
||||||
results = 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
|
# 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?")
|
||||||
|
|
@ -125,8 +127,8 @@ class Hindsight:
|
||||||
|
|
||||||
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'
|
items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id'
|
||||||
document_id: Optional document ID for grouping memories
|
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
||||||
retain_async: If True, process asynchronously in background (default: False)
|
retain_async: If True, process asynchronously in background (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -138,13 +140,14 @@ class Hindsight:
|
||||||
timestamp=item.get("timestamp"),
|
timestamp=item.get("timestamp"),
|
||||||
context=item.get("context"),
|
context=item.get("context"),
|
||||||
metadata=item.get("metadata"),
|
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,
|
||||||
)
|
)
|
||||||
for item in items
|
for item in items
|
||||||
]
|
]
|
||||||
|
|
||||||
request_obj = retain_request.RetainRequest(
|
request_obj = retain_request.RetainRequest(
|
||||||
items=memory_items,
|
items=memory_items,
|
||||||
document_id=document_id,
|
|
||||||
async_=retain_async,
|
async_=retain_async,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -161,6 +164,8 @@ class Hindsight:
|
||||||
query_timestamp: Optional[str] = None,
|
query_timestamp: Optional[str] = None,
|
||||||
include_entities: bool = False,
|
include_entities: bool = False,
|
||||||
max_entity_tokens: int = 500,
|
max_entity_tokens: int = 500,
|
||||||
|
include_chunks: bool = False,
|
||||||
|
max_chunk_tokens: int = 8192,
|
||||||
) -> RecallResponse:
|
) -> RecallResponse:
|
||||||
"""
|
"""
|
||||||
Recall memories using semantic similarity.
|
Recall memories using semantic similarity.
|
||||||
|
|
@ -175,14 +180,17 @@ class Hindsight:
|
||||||
query_timestamp: Optional ISO format date string (e.g., '2023-05-30T23:40:00')
|
query_timestamp: Optional ISO format date string (e.g., '2023-05-30T23:40:00')
|
||||||
include_entities: Include entity observations in results (default: False)
|
include_entities: Include entity observations in results (default: False)
|
||||||
max_entity_tokens: Maximum tokens for entity observations (default: 500)
|
max_entity_tokens: Maximum tokens for entity observations (default: 500)
|
||||||
|
include_chunks: Include raw text chunks in results (default: False)
|
||||||
|
max_chunk_tokens: Maximum tokens for chunks (default: 8192)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
RecallResponse with results, optional entities, and optional trace
|
RecallResponse with results, optional entities, optional chunks, and optional trace
|
||||||
"""
|
"""
|
||||||
from hindsight_client_api.models import include_options, entity_include_options
|
from hindsight_client_api.models import include_options, entity_include_options, chunk_include_options
|
||||||
|
|
||||||
include_opts = include_options.IncludeOptions(
|
include_opts = include_options.IncludeOptions(
|
||||||
entities=entity_include_options.EntityIncludeOptions(max_tokens=max_entity_tokens) if include_entities else None
|
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,
|
||||||
)
|
)
|
||||||
|
|
||||||
request_obj = recall_request.RecallRequest(
|
request_obj = recall_request.RecallRequest(
|
||||||
|
|
@ -277,8 +285,8 @@ class Hindsight:
|
||||||
|
|
||||||
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'
|
items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id'
|
||||||
document_id: Optional document ID for grouping memories
|
document_id: Optional document ID for grouping memories (applied to items that don't have their own)
|
||||||
retain_async: If True, process asynchronously in background (default: False)
|
retain_async: If True, process asynchronously in background (default: False)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
@ -290,13 +298,14 @@ class Hindsight:
|
||||||
timestamp=item.get("timestamp"),
|
timestamp=item.get("timestamp"),
|
||||||
context=item.get("context"),
|
context=item.get("context"),
|
||||||
metadata=item.get("metadata"),
|
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,
|
||||||
)
|
)
|
||||||
for item in items
|
for item in items
|
||||||
]
|
]
|
||||||
|
|
||||||
request_obj = retain_request.RetainRequest(
|
request_obj = retain_request.RetainRequest(
|
||||||
items=memory_items,
|
items=memory_items,
|
||||||
document_id=document_id,
|
|
||||||
async_=retain_async,
|
async_=retain_async,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,17 @@ export class HindsightClient {
|
||||||
async recall(
|
async recall(
|
||||||
bankId: string,
|
bankId: string,
|
||||||
query: string,
|
query: string,
|
||||||
options?: { types?: string[]; maxTokens?: number; budget?: Budget; trace?: boolean }
|
options?: {
|
||||||
|
types?: string[];
|
||||||
|
maxTokens?: number;
|
||||||
|
budget?: Budget;
|
||||||
|
trace?: boolean;
|
||||||
|
queryTimestamp?: string;
|
||||||
|
includeEntities?: boolean;
|
||||||
|
maxEntityTokens?: number;
|
||||||
|
includeChunks?: boolean;
|
||||||
|
maxChunkTokens?: number;
|
||||||
|
}
|
||||||
): Promise<RecallResponse> {
|
): Promise<RecallResponse> {
|
||||||
const response = await sdk.recallMemories({
|
const response = await sdk.recallMemories({
|
||||||
client: this.client,
|
client: this.client,
|
||||||
|
|
@ -139,6 +149,11 @@ export class HindsightClient {
|
||||||
max_tokens: options?.maxTokens,
|
max_tokens: options?.maxTokens,
|
||||||
budget: options?.budget || 'mid',
|
budget: options?.budget || 'mid',
|
||||||
trace: options?.trace,
|
trace: options?.trace,
|
||||||
|
query_timestamp: options?.queryTimestamp,
|
||||||
|
include: {
|
||||||
|
entities: options?.includeEntities ? { max_tokens: options?.maxEntityTokens ?? 500 } : undefined,
|
||||||
|
chunks: options?.includeChunks ? { max_tokens: options?.maxChunkTokens ?? 8192 } : undefined,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
---
|
|
||||||
sidebar_position: 4
|
|
||||||
---
|
|
||||||
|
|
||||||
# Think vs Search
|
|
||||||
|
|
||||||
When to use `search` vs `think`.
|
|
||||||
|
|
||||||
## Quick Comparison
|
|
||||||
|
|
||||||
| | Search | Think |
|
|
||||||
|---|--------|-------|
|
|
||||||
| **Returns** | Raw memory results | Generated response |
|
|
||||||
| **Use case** | Retrieval, lookup | Q&A, reasoning |
|
|
||||||
| **LLM calls** | 0 (retrieval only) | 1+ (generation) |
|
|
||||||
| **Speed** | Fast (~100-200ms) | Slower (~500-2000ms) |
|
|
||||||
| **Opinions** | Returns existing | Can form new ones |
|
|
||||||
| **Disposition** | Not applied | Applied to response |
|
|
||||||
|
|
||||||
## When to Use Search
|
|
||||||
|
|
||||||
**Use Search when you need:**
|
|
||||||
|
|
||||||
- Raw facts for your own processing
|
|
||||||
- Fast retrieval without generation
|
|
||||||
- To populate context for another LLM
|
|
||||||
- To check what's in memory
|
|
||||||
- Debugging retrieval quality
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Get raw facts to inject into your own prompt
|
|
||||||
results = client.search(agent_id="my-agent", query="Alice's preferences")
|
|
||||||
|
|
||||||
context = "\n".join([r["text"] for r in results])
|
|
||||||
# Use context in your own LLM call
|
|
||||||
```
|
|
||||||
|
|
||||||
**Examples:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Lookup — just get the facts
|
|
||||||
results = client.search(agent_id="my-agent", query="Alice's email address")
|
|
||||||
|
|
||||||
# Context building — feed into another system
|
|
||||||
results = client.search(agent_id="my-agent", query="Recent project discussions")
|
|
||||||
context = format_for_prompt(results)
|
|
||||||
|
|
||||||
# Verification — check what's stored
|
|
||||||
results = client.search(agent_id="my-agent", query="What do I know about Bob?")
|
|
||||||
```
|
|
||||||
|
|
||||||
## When to Use Think
|
|
||||||
|
|
||||||
**Use Think when you need:**
|
|
||||||
|
|
||||||
- A natural language response
|
|
||||||
- Disposition-aware answers
|
|
||||||
- Opinion formation
|
|
||||||
- Reasoning over multiple facts
|
|
||||||
- Source attribution
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Get a complete answer with disposition
|
|
||||||
answer = client.think(agent_id="my-agent", query="What should I recommend to Alice?")
|
|
||||||
print(answer["text"]) # Natural language response
|
|
||||||
print(answer["based_on"]) # Sources used
|
|
||||||
```
|
|
||||||
|
|
||||||
**Examples:**
|
|
||||||
|
|
||||||
```python
|
|
||||||
# Q&A — need a response, not just facts
|
|
||||||
answer = client.think(agent_id="my-agent", query="What does Alice do for work?")
|
|
||||||
|
|
||||||
# Reasoning — synthesize multiple facts
|
|
||||||
answer = client.think(agent_id="my-agent", query="How are Alice and Bob connected?")
|
|
||||||
|
|
||||||
# Opinion — agent forms a view
|
|
||||||
answer = client.think(agent_id="my-agent", query="What do you think about Python?")
|
|
||||||
|
|
||||||
# Recommendation — disposition-influenced
|
|
||||||
answer = client.think(agent_id="my-agent", query="What book should I read next?")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Performance Comparison
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph LR
|
|
||||||
subgraph Search
|
|
||||||
S1[Query] --> S2[4-way Retrieval]
|
|
||||||
S2 --> S3[RRF + Rerank]
|
|
||||||
S3 --> S4[Results]
|
|
||||||
end
|
|
||||||
|
|
||||||
subgraph Think
|
|
||||||
T1[Query] --> T2[4-way Retrieval]
|
|
||||||
T2 --> T3[RRF + Rerank]
|
|
||||||
T3 --> T4[Load Disposition]
|
|
||||||
T4 --> T5[LLM Generation]
|
|
||||||
T5 --> T6[Store Opinions]
|
|
||||||
T6 --> T7[Response]
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
| Operation | Search | Think |
|
|
||||||
|-----------|--------|-------|
|
|
||||||
| Retrieval | ~100ms | ~100ms |
|
|
||||||
| Reranking | ~35ms | ~35ms |
|
|
||||||
| LLM Generation | — | ~500-1500ms |
|
|
||||||
| Opinion Storage | — | ~50ms |
|
|
||||||
| **Total** | **~135ms** | **~700-1700ms** |
|
|
||||||
|
|
||||||
## Hybrid Pattern
|
|
||||||
|
|
||||||
Use Search for context, Think for final response:
|
|
||||||
|
|
||||||
```python
|
|
||||||
# First: fast search to check relevance
|
|
||||||
results = client.search(agent_id="my-agent", query="Alice project status")
|
|
||||||
|
|
||||||
if len(results) > 0:
|
|
||||||
# Only call Think if we have relevant memories
|
|
||||||
answer = client.think(agent_id="my-agent", query="Summarize Alice's project status")
|
|
||||||
else:
|
|
||||||
answer = {"text": "I don't have information about Alice's projects."}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Decision Flowchart
|
|
||||||
|
|
||||||
```mermaid
|
|
||||||
graph TD
|
|
||||||
A[Need memory access] --> B{Need natural language response?}
|
|
||||||
B -->|No| C[Use Search]
|
|
||||||
B -->|Yes| D{Need disposition/opinions?}
|
|
||||||
D -->|No| E{Building context for another LLM?}
|
|
||||||
E -->|Yes| C
|
|
||||||
E -->|No| F[Use Think]
|
|
||||||
D -->|Yes| F
|
|
||||||
```
|
|
||||||
|
|
||||||
## Cost Considerations
|
|
||||||
|
|
||||||
| Factor | Search | Think |
|
|
||||||
|--------|--------|-------|
|
|
||||||
| API calls | 1 | 1 |
|
|
||||||
| LLM tokens | 0 | 500-2000 |
|
|
||||||
| Latency | Low | Medium |
|
|
||||||
| Cost | Low | Higher (LLM usage) |
|
|
||||||
|
|
||||||
If you're making many requests or building a high-throughput system, consider:
|
|
||||||
- Use Search for bulk operations
|
|
||||||
- Use Think for user-facing responses
|
|
||||||
- Cache Think responses when appropriate
|
|
||||||
|
|
@ -55,27 +55,29 @@ docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
**Best for**: Production deployments, auto-scaling, cloud environments
|
**Best for**: Production deployments, auto-scaling, cloud environments
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add Hindsight Helm repository
|
|
||||||
helm repo add hindsight https://vectorize-io.github.io/hindsight
|
|
||||||
helm repo update
|
|
||||||
|
|
||||||
# Install with built-in PostgreSQL
|
# Install with built-in PostgreSQL
|
||||||
helm install hindsight hindsight/hindsight \
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
|
||||||
--set api.llm.provider=groq \
|
--set api.llm.provider=groq \
|
||||||
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
||||||
--set postgresql.enabled=true
|
--set postgresql.enabled=true
|
||||||
|
|
||||||
# Or use external PostgreSQL
|
# Or use external PostgreSQL
|
||||||
helm install hindsight hindsight/hindsight \
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
|
||||||
--set api.llm.provider=groq \
|
--set api.llm.provider=groq \
|
||||||
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
||||||
--set postgresql.enabled=false \
|
--set postgresql.enabled=false \
|
||||||
--set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight
|
--set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight
|
||||||
|
|
||||||
|
# Install a specific version
|
||||||
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight --version 0.1.3
|
||||||
|
|
||||||
|
# Upgrade to latest
|
||||||
|
helm upgrade hindsight oci://ghcr.io/vectorize-io/charts/hindsight
|
||||||
```
|
```
|
||||||
|
|
||||||
**Requirements**:
|
**Requirements**:
|
||||||
- Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
|
- Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
|
||||||
- Helm 3+
|
- Helm 3.8+
|
||||||
|
|
||||||
See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
|
See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,21 +15,21 @@ npm install @vectorize-io/hindsight-client
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
const { HindsightClient } = require('@vectorize-io/hindsight-client');
|
||||||
|
|
||||||
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
||||||
|
|
||||||
// Retain a memory
|
// Retain a memory
|
||||||
await client.retain('my-agent', 'Alice works at Google');
|
await client.retain('my-bank', 'Alice works at Google');
|
||||||
|
|
||||||
// Recall memories
|
// Recall memories
|
||||||
const response = await client.recall('my-agent', 'What does Alice do?');
|
const response = await client.recall('my-bank', 'What does Alice do?');
|
||||||
for (const r of response.results) {
|
for (const r of response.results) {
|
||||||
console.log(r.text);
|
console.log(r.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reflect - generate response with disposition
|
// Reflect - generate response with disposition
|
||||||
const answer = await client.reflect('my-agent', 'Tell me about Alice');
|
const answer = await client.reflect('my-bank', 'Tell me about Alice');
|
||||||
console.log(answer.text);
|
console.log(answer.text);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -49,10 +49,10 @@ const client = new HindsightClient({
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Simple
|
// Simple
|
||||||
await client.retain('my-agent', 'Alice works at Google');
|
await client.retain('my-bank', 'Alice works at Google');
|
||||||
|
|
||||||
// With options
|
// With options
|
||||||
await client.retain('my-agent', 'Alice got promoted', {
|
await client.retain('my-bank', 'Alice got promoted', {
|
||||||
timestamp: new Date('2024-01-15'),
|
timestamp: new Date('2024-01-15'),
|
||||||
context: 'career update',
|
context: 'career update',
|
||||||
metadata: { source: 'slack' },
|
metadata: { source: 'slack' },
|
||||||
|
|
@ -63,11 +63,10 @@ await client.retain('my-agent', 'Alice got promoted', {
|
||||||
### Retain Batch
|
### Retain Batch
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
await client.retainBatch('my-agent', [
|
await client.retainBatch('my-bank', [
|
||||||
{ content: 'Alice works at Google', context: 'career' },
|
{ content: 'Alice works at Google', context: 'career' },
|
||||||
{ content: 'Bob is a data scientist', context: 'career' },
|
{ content: 'Bob is a data scientist', context: 'career' },
|
||||||
], {
|
], {
|
||||||
documentId: 'conversation_001',
|
|
||||||
async: false,
|
async: false,
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
@ -76,31 +75,29 @@ await client.retainBatch('my-agent', [
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// Simple - returns RecallResponse
|
// Simple - returns RecallResponse
|
||||||
const response = await client.recall('my-agent', 'What does Alice do?');
|
const response = await client.recall('my-bank', 'What does Alice do?');
|
||||||
|
|
||||||
for (const r of response.results) {
|
for (const r of response.results) {
|
||||||
console.log(`${r.text} (type: ${r.type})`);
|
console.log(`${r.text} (type: ${r.type})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// With options
|
// With options
|
||||||
const response = await client.recall('my-agent', 'What does Alice do?', {
|
const response = await client.recall('my-bank', 'What does Alice do?', {
|
||||||
types: ['world', 'opinion'], // Filter by fact type
|
types: ['world', 'opinion'], // Filter by fact type
|
||||||
maxTokens: 4096,
|
maxTokens: 4096,
|
||||||
budget: 'high', // 'low', 'mid', or 'high'
|
budget: 'high', // 'low', 'mid', or 'high'
|
||||||
trace: true,
|
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Reflect (Generate Response)
|
### Reflect (Generate Response)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const answer = await client.reflect('my-agent', 'What should I know about Alice?', {
|
const answer = await client.reflect('my-bank', 'What should I know about Alice?', {
|
||||||
budget: 'low', // 'low', 'mid', or 'high'
|
budget: 'low', // 'low', 'mid', or 'high'
|
||||||
context: 'preparing for a meeting',
|
context: 'preparing for a meeting',
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(answer.text); // Generated response
|
console.log(answer.text); // Generated response
|
||||||
console.log(answer.based_on); // Memories used
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Bank Management
|
## Bank Management
|
||||||
|
|
@ -108,7 +105,7 @@ console.log(answer.based_on); // Memories used
|
||||||
### Create Bank
|
### Create Bank
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
await client.createBank('my-agent', {
|
await client.createBank('my-bank', {
|
||||||
name: 'Assistant',
|
name: 'Assistant',
|
||||||
background: 'I am a helpful AI assistant',
|
background: 'I am a helpful AI assistant',
|
||||||
disposition: {
|
disposition: {
|
||||||
|
|
@ -119,117 +116,14 @@ await client.createBank('my-agent', {
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Get Bank Profile
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
const profile = await client.getBankProfile('my-agent');
|
|
||||||
console.log(profile.disposition);
|
|
||||||
console.log(profile.background);
|
|
||||||
```
|
|
||||||
|
|
||||||
### List Memories
|
### List Memories
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
const response = await client.listMemories('my-agent', {
|
const response = await client.listMemories('my-bank', {
|
||||||
type: 'world', // Optional filter
|
type: 'world', // Optional filter
|
||||||
q: 'Alice', // Optional text search
|
q: 'Alice', // Optional text search
|
||||||
limit: 100,
|
limit: 100,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
});
|
});
|
||||||
|
console.log(response)
|
||||||
for (const memory of response.memories) {
|
|
||||||
console.log(`${memory.id}: ${memory.text}`);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## TypeScript Types
|
|
||||||
|
|
||||||
The client exports all types for full TypeScript support:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import type {
|
|
||||||
RetainResponse,
|
|
||||||
RecallResponse,
|
|
||||||
RecallResult,
|
|
||||||
ReflectResponse,
|
|
||||||
BankProfileResponse,
|
|
||||||
Budget,
|
|
||||||
} from '@vectorize-io/hindsight-client';
|
|
||||||
|
|
||||||
// Budget is a union type: 'low' | 'mid' | 'high'
|
|
||||||
const budget: Budget = 'mid';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Advanced: Low-Level SDK
|
|
||||||
|
|
||||||
For advanced use cases, access the auto-generated SDK directly:
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { sdk, createClient, createConfig } from '@vectorize-io/hindsight-client';
|
|
||||||
|
|
||||||
const client = createClient(createConfig({ baseUrl: 'http://localhost:8888' }));
|
|
||||||
|
|
||||||
// Use sdk functions directly
|
|
||||||
const response = await sdk.recallMemories({
|
|
||||||
client,
|
|
||||||
path: { bank_id: 'my-agent' },
|
|
||||||
body: {
|
|
||||||
query: 'What does Alice do?',
|
|
||||||
budget: 'mid',
|
|
||||||
max_tokens: 4096,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
|
||||||
|
|
||||||
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client.recall('unknown-agent', 'test');
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error:', error.message);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Example: Full Workflow
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import { HindsightClient } from '@vectorize-io/hindsight-client';
|
|
||||||
|
|
||||||
async function main() {
|
|
||||||
const client = new HindsightClient({ baseUrl: 'http://localhost:8888' });
|
|
||||||
|
|
||||||
// Create a bank with disposition
|
|
||||||
await client.createBank('demo', {
|
|
||||||
name: 'Demo Agent',
|
|
||||||
background: 'A helpful assistant for demos',
|
|
||||||
disposition: {
|
|
||||||
skepticism: 2, // Trusting
|
|
||||||
literalism: 3, // Balanced
|
|
||||||
empathy: 4, // Empathetic
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// Store some memories
|
|
||||||
await client.retain('demo', 'Alice works at Google');
|
|
||||||
await client.retain('demo', 'Bob is a data scientist at Google');
|
|
||||||
await client.retain('demo', 'Alice and Bob collaborate on ML projects');
|
|
||||||
|
|
||||||
// Search for memories
|
|
||||||
const searchResults = await client.recall('demo', 'Who works at Google?');
|
|
||||||
console.log('Search results:');
|
|
||||||
for (const r of searchResults.results) {
|
|
||||||
console.log(` - ${r.text}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a response
|
|
||||||
const answer = await client.reflect('demo', 'What do you know about the team?');
|
|
||||||
console.log('\nReflection:', answer.text);
|
|
||||||
}
|
|
||||||
|
|
||||||
main().catch(console.error);
|
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -49,15 +49,15 @@ with HindsightServer(
|
||||||
client = HindsightClient(base_url=server.url)
|
client = HindsightClient(base_url=server.url)
|
||||||
|
|
||||||
# Retain a memory
|
# Retain a memory
|
||||||
client.retain(bank_id="my-agent", content="Alice works at Google")
|
client.retain(bank_id="my-bank", content="Alice works at Google")
|
||||||
|
|
||||||
# Recall memories
|
# Recall memories
|
||||||
results = client.recall(bank_id="my-agent", query="What does Alice do?")
|
results = client.recall(bank_id="my-bank", query="What does Alice do?")
|
||||||
for r in results:
|
for r in results:
|
||||||
print(r.text)
|
print(r.text)
|
||||||
|
|
||||||
# Reflect - generate response with disposition
|
# Reflect - generate response with disposition
|
||||||
answer = client.reflect(bank_id="my-agent", query="Tell me about Alice")
|
answer = client.reflect(bank_id="my-bank", query="Tell me about Alice")
|
||||||
print(answer.text)
|
print(answer.text)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -70,15 +70,15 @@ from hindsight_client import Hindsight
|
||||||
client = Hindsight(base_url="http://localhost:8888")
|
client = Hindsight(base_url="http://localhost:8888")
|
||||||
|
|
||||||
# Retain a memory
|
# Retain a memory
|
||||||
client.retain(bank_id="my-agent", content="Alice works at Google")
|
client.retain(bank_id="my-bank", content="Alice works at Google")
|
||||||
|
|
||||||
# Recall memories
|
# Recall memories
|
||||||
results = client.recall(bank_id="my-agent", query="What does Alice do?")
|
results = client.recall(bank_id="my-bank", query="What does Alice do?")
|
||||||
for r in results:
|
for r in results:
|
||||||
print(r.text)
|
print(r.text)
|
||||||
|
|
||||||
# Reflect - generate response with disposition
|
# Reflect - generate response with disposition
|
||||||
answer = client.reflect(bank_id="my-agent", query="Tell me about Alice")
|
answer = client.reflect(bank_id="my-bank", query="Tell me about Alice")
|
||||||
print(answer.text)
|
print(answer.text)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -103,7 +103,7 @@ client = Hindsight(
|
||||||
```python
|
```python
|
||||||
# Simple
|
# Simple
|
||||||
client.retain(
|
client.retain(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
content="Alice works at Google as a software engineer",
|
content="Alice works at Google as a software engineer",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -111,7 +111,7 @@ client.retain(
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
client.retain(
|
client.retain(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
content="Alice got promoted",
|
content="Alice got promoted",
|
||||||
context="career update",
|
context="career update",
|
||||||
timestamp=datetime(2024, 1, 15),
|
timestamp=datetime(2024, 1, 15),
|
||||||
|
|
@ -124,7 +124,7 @@ client.retain(
|
||||||
|
|
||||||
```python
|
```python
|
||||||
client.retain_batch(
|
client.retain_batch(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
items=[
|
items=[
|
||||||
{"content": "Alice works at Google", "context": "career"},
|
{"content": "Alice works at Google", "context": "career"},
|
||||||
{"content": "Bob is a data scientist", "context": "career"},
|
{"content": "Bob is a data scientist", "context": "career"},
|
||||||
|
|
@ -139,16 +139,16 @@ client.retain_batch(
|
||||||
```python
|
```python
|
||||||
# Simple - returns list of RecallResult
|
# Simple - returns list of RecallResult
|
||||||
results = client.recall(
|
results = client.recall(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
query="What does Alice do?",
|
query="What does Alice do?",
|
||||||
)
|
)
|
||||||
|
|
||||||
for r in results:
|
for r in results.results:
|
||||||
print(f"{r.text} (type: {r.type})")
|
print(f"{r.text} (type: {r.type})")
|
||||||
|
|
||||||
# With options
|
# With options
|
||||||
results = client.recall(
|
results = client.recall(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
query="What does Alice do?",
|
query="What does Alice do?",
|
||||||
types=["world", "opinion"], # Filter by fact type
|
types=["world", "opinion"], # Filter by fact type
|
||||||
max_tokens=4096,
|
max_tokens=4096,
|
||||||
|
|
@ -159,16 +159,15 @@ results = client.recall(
|
||||||
### Recall with Full Response
|
### Recall with Full Response
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Returns RecallResponse with entities and trace info
|
# Returns RecallResponse with entities and chunks
|
||||||
response = client.recall_memories(
|
response = client.recall(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
query="What does Alice do?",
|
query="What does Alice do?",
|
||||||
types=["world", "experience"],
|
types=["world", "experience"],
|
||||||
budget="mid",
|
budget="mid",
|
||||||
max_tokens=4096,
|
max_tokens=4096,
|
||||||
trace=True,
|
|
||||||
include_entities=True,
|
include_entities=True,
|
||||||
max_entity_tokens=500,
|
max_entity_tokens=500
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"Found {len(response.results)} memories")
|
print(f"Found {len(response.results)} memories")
|
||||||
|
|
@ -185,14 +184,13 @@ if response.entities:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
answer = client.reflect(
|
answer = client.reflect(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
query="What should I know about Alice?",
|
query="What should I know about Alice?",
|
||||||
budget="low", # low, mid, or high
|
budget="low", # low, mid, or high
|
||||||
context="preparing for a meeting",
|
context="preparing for a meeting",
|
||||||
)
|
)
|
||||||
|
|
||||||
print(answer.text) # Generated response
|
print(answer.text) # Generated response
|
||||||
print(answer.based_on) # Memories used
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Bank Management
|
## Bank Management
|
||||||
|
|
@ -201,7 +199,7 @@ print(answer.based_on) # Memories used
|
||||||
|
|
||||||
```python
|
```python
|
||||||
client.create_bank(
|
client.create_bank(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
name="Assistant",
|
name="Assistant",
|
||||||
background="I am a helpful AI assistant",
|
background="I am a helpful AI assistant",
|
||||||
disposition={
|
disposition={
|
||||||
|
|
@ -215,16 +213,13 @@ client.create_bank(
|
||||||
### List Memories
|
### List Memories
|
||||||
|
|
||||||
```python
|
```python
|
||||||
response = client.list_memories(
|
client.list_memories(
|
||||||
bank_id="my-agent",
|
bank_id="my-bank",
|
||||||
type="world", # Optional: filter by type
|
type="world", # Optional: filter by type
|
||||||
search_query="Alice", # Optional: text search
|
search_query="Alice", # Optional: text search
|
||||||
limit=100,
|
limit=100,
|
||||||
offset=0,
|
offset=0,
|
||||||
)
|
)
|
||||||
|
|
||||||
for memory in response.memories:
|
|
||||||
print(f"{memory.id}: {memory.text}")
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Async Support
|
## Async Support
|
||||||
|
|
@ -239,15 +234,15 @@ async def main():
|
||||||
client = Hindsight(base_url="http://localhost:8888")
|
client = Hindsight(base_url="http://localhost:8888")
|
||||||
|
|
||||||
# Async retain
|
# Async retain
|
||||||
await client.aretain(bank_id="my-agent", content="Hello world")
|
await client.aretain(bank_id="my-bank", content="Hello world")
|
||||||
|
|
||||||
# Async recall
|
# Async recall
|
||||||
results = await client.arecall(bank_id="my-agent", query="Hello")
|
results = await client.arecall(bank_id="my-bank", query="Hello")
|
||||||
for r in results:
|
for r in results:
|
||||||
print(r.text)
|
print(r.text)
|
||||||
|
|
||||||
# Async reflect
|
# Async reflect
|
||||||
answer = await client.areflect(bank_id="my-agent", query="What did I say?")
|
answer = await client.areflect(bank_id="my-bank", query="What did I say?")
|
||||||
print(answer.text)
|
print(answer.text)
|
||||||
|
|
||||||
client.close()
|
client.close()
|
||||||
|
|
@ -255,29 +250,13 @@ async def main():
|
||||||
asyncio.run(main())
|
asyncio.run(main())
|
||||||
```
|
```
|
||||||
|
|
||||||
## Response Types
|
|
||||||
|
|
||||||
The client exports response types for type hints:
|
|
||||||
|
|
||||||
```python
|
|
||||||
from hindsight_client import (
|
|
||||||
Hindsight,
|
|
||||||
RetainResponse,
|
|
||||||
RecallResponse,
|
|
||||||
RecallResult,
|
|
||||||
ReflectResponse,
|
|
||||||
BankProfileResponse,
|
|
||||||
DispositionTraits,
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
## Context Manager
|
## Context Manager
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from hindsight_client import Hindsight
|
from hindsight_client import Hindsight
|
||||||
|
|
||||||
with Hindsight(base_url="http://localhost:8888") as client:
|
with Hindsight(base_url="http://localhost:8888") as client:
|
||||||
client.retain(bank_id="my-agent", content="Hello")
|
client.retain(bank_id="my-bank", content="Hello")
|
||||||
results = client.recall(bank_id="my-agent", query="Hello")
|
results = client.recall(bank_id="my-bank", query="Hello")
|
||||||
# Client automatically closed
|
# Client automatically closed
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -128,39 +128,38 @@ const config: Config = {
|
||||||
},
|
},
|
||||||
items: [
|
items: [
|
||||||
{
|
{
|
||||||
type: 'custom-iconLink',
|
type: 'doc',
|
||||||
|
docId: 'developer/index',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
icon: 'code',
|
|
||||||
label: 'Developer',
|
label: 'Developer',
|
||||||
to: '/',
|
className: 'navbar-item-developer',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'custom-iconLink',
|
type: 'doc',
|
||||||
|
docId: 'sdks/python',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
icon: 'package',
|
|
||||||
label: 'SDKs',
|
label: 'SDKs',
|
||||||
to: '/sdks/python',
|
className: 'navbar-item-sdks',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'custom-iconLink',
|
|
||||||
position: 'left',
|
|
||||||
icon: 'file-code',
|
|
||||||
label: 'API Reference',
|
|
||||||
to: '/api-reference',
|
to: '/api-reference',
|
||||||
|
position: 'left',
|
||||||
|
label: 'API Reference',
|
||||||
|
className: 'navbar-item-api',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'custom-iconLink',
|
type: 'doc',
|
||||||
|
docId: 'cookbook/index',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
icon: 'book-open',
|
|
||||||
label: 'Cookbook',
|
label: 'Cookbook',
|
||||||
to: '/cookbook',
|
className: 'navbar-item-cookbook',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'custom-iconLink',
|
type: 'doc',
|
||||||
|
docId: 'changelog/index',
|
||||||
position: 'left',
|
position: 'left',
|
||||||
icon: 'clock',
|
|
||||||
label: 'Changelog',
|
label: 'Changelog',
|
||||||
to: '/changelog',
|
className: 'navbar-item-changelog',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
href: 'https://github.com/vectorize-io/hindsight',
|
href: 'https://github.com/vectorize-io/hindsight',
|
||||||
|
|
@ -200,7 +199,7 @@ const config: Config = {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
copyright: `Copyright © ${new Date().getFullYear()} Hindsight. Built with Docusaurus.`,
|
copyright: `Copyright © ${new Date().getFullYear()} Hindsight.`,
|
||||||
},
|
},
|
||||||
prism: {
|
prism: {
|
||||||
theme: prismThemes.github,
|
theme: prismThemes.github,
|
||||||
|
|
|
||||||
14
hindsight-docs/package-lock.json
generated
14
hindsight-docs/package-lock.json
generated
|
|
@ -13,7 +13,6 @@
|
||||||
"@docusaurus/theme-common": "^3.9.2",
|
"@docusaurus/theme-common": "^3.9.2",
|
||||||
"@docusaurus/theme-mermaid": "^3.9.2",
|
"@docusaurus/theme-mermaid": "^3.9.2",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"@phosphor-icons/react": "^2.1.10",
|
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.3.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|
@ -4534,19 +4533,6 @@
|
||||||
"node": ">=8.0.0"
|
"node": ">=8.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@phosphor-icons/react": {
|
|
||||||
"version": "2.1.10",
|
|
||||||
"resolved": "https://registry.npmjs.org/@phosphor-icons/react/-/react-2.1.10.tgz",
|
|
||||||
"integrity": "sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 16.8",
|
|
||||||
"react-dom": ">= 16.8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@pnpm/config.env-replace": {
|
"node_modules/@pnpm/config.env-replace": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz",
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@
|
||||||
"@docusaurus/theme-common": "^3.9.2",
|
"@docusaurus/theme-common": "^3.9.2",
|
||||||
"@docusaurus/theme-mermaid": "^3.9.2",
|
"@docusaurus/theme-mermaid": "^3.9.2",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"@phosphor-icons/react": "^2.1.10",
|
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.3.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
import React from 'react';
|
|
||||||
import Link from '@docusaurus/Link';
|
|
||||||
import {
|
|
||||||
House,
|
|
||||||
Code,
|
|
||||||
Package,
|
|
||||||
FileCode,
|
|
||||||
BookOpen,
|
|
||||||
ClockCounterClockwise,
|
|
||||||
} from '@phosphor-icons/react';
|
|
||||||
|
|
||||||
const iconMap = {
|
|
||||||
house: House,
|
|
||||||
code: Code,
|
|
||||||
package: Package,
|
|
||||||
'file-code': FileCode,
|
|
||||||
'book-open': BookOpen,
|
|
||||||
clock: ClockCounterClockwise,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function NavbarIconLink({
|
|
||||||
icon,
|
|
||||||
label,
|
|
||||||
to,
|
|
||||||
className,
|
|
||||||
}: {
|
|
||||||
icon: keyof typeof iconMap;
|
|
||||||
label: string;
|
|
||||||
to: string;
|
|
||||||
className?: string;
|
|
||||||
}) {
|
|
||||||
const IconComponent = iconMap[icon];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link to={to} className={`navbar__link ${className || ''}`}>
|
|
||||||
{IconComponent && (
|
|
||||||
<IconComponent size={16} weight="bold" style={{ marginRight: '6px', verticalAlign: 'middle' }} />
|
|
||||||
)}
|
|
||||||
<span style={{ verticalAlign: 'middle' }}>{label}</span>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -94,6 +94,66 @@
|
||||||
transition: background-color 0.15s ease;
|
transition: background-color 0.15s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Navbar icons (desktop only) */
|
||||||
|
@media (min-width: 997px) {
|
||||||
|
.navbar-item-developer::before,
|
||||||
|
.navbar-item-sdks::before,
|
||||||
|
.navbar-item-api::before,
|
||||||
|
.navbar-item-cookbook::before,
|
||||||
|
.navbar-item-changelog::before {
|
||||||
|
display: inline-block;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
margin-right: 6px;
|
||||||
|
vertical-align: middle;
|
||||||
|
background-size: contain;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item-developer::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M71.68 97.22 34.74 128l36.94 30.78a12 12 0 1 1-15.36 18.44l-48-40a12 12 0 0 1 0-18.44l48-40a12 12 0 0 1 15.36 18.44Zm176 21.56-48-40a12 12 0 1 0-15.36 18.44L221.26 128l-36.94 30.78a12 12 0 1 0 15.36 18.44l48-40a12 12 0 0 0 0-18.44ZM164.1 28.72a12 12 0 0 0-15.38 7.18l-64 176a12 12 0 0 0 7.18 15.37 11.79 11.79 0 0 0 4.1.73 12 12 0 0 0 11.28-7.9l64-176a12 12 0 0 0-7.18-15.38Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item-sdks::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='m225.6 62.64-88-48.17a19.91 19.91 0 0 0-19.2 0l-88 48.17A20 20 0 0 0 20 80.19v95.62a20 20 0 0 0 10.4 17.55l88 48.17a19.89 19.89 0 0 0 19.2 0l88-48.17a20 20 0 0 0 10.4-17.55V80.19a20 20 0 0 0-10.4-17.55ZM128 36.57 200 76l-72 39.42L56 76ZM44 96.82l72 39.43v76.89l-72-39.42Zm96 116.32v-76.89l72-39.43v76.89Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item-api::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M180.49 143.51a12 12 0 0 1 0 17l-24 24a12 12 0 0 1-17-17L155 152l-15.52-15.51a12 12 0 0 1 17-17ZM112.49 120.49a12 12 0 0 0-17 0l-24 24a12 12 0 0 0 0 17l24 24a12 12 0 0 0 17-17L97 153l15.52-15.51a12 12 0 0 0-.03-17ZM220 88v24a12 12 0 0 1-24 0v-16h-44a12 12 0 0 1-12-12V40H60v68a12 12 0 0 1-24 0V40a20 20 0 0 1 20-20h96a12 12 0 0 1 8.49 3.52l56 56A12 12 0 0 1 220 88Zm-60-8h23L160 57Zm-4 132H60v-12a12 12 0 0 0-24 0v12a20 20 0 0 0 20 20h100a12 12 0 0 0 0-24Zm64-44a12 12 0 0 0-12 12v36h-44a12 12 0 0 0 0 24h44a20 20 0 0 0 20-20v-40a12 12 0 0 0-8-12Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item-cookbook::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M224 44H160a43.86 43.86 0 0 0-32 13.85A43.86 43.86 0 0 0 96 44H32a20 20 0 0 0-20 20v128a20 20 0 0 0 20 20h64a20 20 0 0 1 20 20 12 12 0 0 0 24 0 20 20 0 0 1 20-20h64a20 20 0 0 0 20-20V64a20 20 0 0 0-20-20ZM96 188H36V68h60a20 20 0 0 1 20 20v108.69A43.74 43.74 0 0 0 96 188Zm124 0h-60a43.74 43.74 0 0 0-20 8.69V88a20 20 0 0 1 20-20h60Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-item-changelog::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23666' d='M140 80v41.21l34.17 20.5a12 12 0 1 1-12.34 20.58l-40-24A12 12 0 0 1 116 128V80a12 12 0 0 1 24 0Zm-12-52a99.38 99.38 0 0 0-70.76 29.34c-4.69 4.74-9 9.37-13.24 14V64a12 12 0 0 0-24 0v40a12 12 0 0 0 12 12h40a12 12 0 0 0 0-24H53.41c4.24-5.95 8.53-11.93 13.49-16.95A76 76 0 1 1 52 128a12 12 0 0 0-24 0 100 100 0 1 0 100-100Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode icons */
|
||||||
|
[data-theme='dark'] .navbar-item-developer::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M71.68 97.22 34.74 128l36.94 30.78a12 12 0 1 1-15.36 18.44l-48-40a12 12 0 0 1 0-18.44l48-40a12 12 0 0 1 15.36 18.44Zm176 21.56-48-40a12 12 0 1 0-15.36 18.44L221.26 128l-36.94 30.78a12 12 0 1 0 15.36 18.44l48-40a12 12 0 0 0 0-18.44ZM164.1 28.72a12 12 0 0 0-15.38 7.18l-64 176a12 12 0 0 0 7.18 15.37 11.79 11.79 0 0 0 4.1.73 12 12 0 0 0 11.28-7.9l64-176a12 12 0 0 0-7.18-15.38Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-item-sdks::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='m225.6 62.64-88-48.17a19.91 19.91 0 0 0-19.2 0l-88 48.17A20 20 0 0 0 20 80.19v95.62a20 20 0 0 0 10.4 17.55l88 48.17a19.89 19.89 0 0 0 19.2 0l88-48.17a20 20 0 0 0 10.4-17.55V80.19a20 20 0 0 0-10.4-17.55ZM128 36.57 200 76l-72 39.42L56 76ZM44 96.82l72 39.43v76.89l-72-39.42Zm96 116.32v-76.89l72-39.43v76.89Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-item-api::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M180.49 143.51a12 12 0 0 1 0 17l-24 24a12 12 0 0 1-17-17L155 152l-15.52-15.51a12 12 0 0 1 17-17ZM112.49 120.49a12 12 0 0 0-17 0l-24 24a12 12 0 0 0 0 17l24 24a12 12 0 0 0 17-17L97 153l15.52-15.51a12 12 0 0 0-.03-17ZM220 88v24a12 12 0 0 1-24 0v-16h-44a12 12 0 0 1-12-12V40H60v68a12 12 0 0 1-24 0V40a20 20 0 0 1 20-20h96a12 12 0 0 1 8.49 3.52l56 56A12 12 0 0 1 220 88Zm-60-8h23L160 57Zm-4 132H60v-12a12 12 0 0 0-24 0v12a20 20 0 0 0 20 20h100a12 12 0 0 0 0-24Zm64-44a12 12 0 0 0-12 12v36h-44a12 12 0 0 0 0 24h44a20 20 0 0 0 20-20v-40a12 12 0 0 0-8-12Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-item-cookbook::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M224 44H160a43.86 43.86 0 0 0-32 13.85A43.86 43.86 0 0 0 96 44H32a20 20 0 0 0-20 20v128a20 20 0 0 0 20 20h64a20 20 0 0 1 20 20 12 12 0 0 0 24 0 20 20 0 0 1 20-20h64a20 20 0 0 0 20-20V64a20 20 0 0 0-20-20ZM96 188H36V68h60a20 20 0 0 1 20 20v108.69A43.74 43.74 0 0 0 96 188Zm124 0h-60a43.74 43.74 0 0 0-20 8.69V88a20 20 0 0 1 20-20h60Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-item-changelog::before {
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath fill='%23ccc' d='M140 80v41.21l34.17 20.5a12 12 0 1 1-12.34 20.58l-40-24A12 12 0 0 1 116 128V80a12 12 0 0 1 24 0Zm-12-52a99.38 99.38 0 0 0-70.76 29.34c-4.69 4.74-9 9.37-13.24 14V64a12 12 0 0 0-24 0v40a12 12 0 0 0 12 12h40a12 12 0 0 0 0-24H53.41c4.24-5.95 8.53-11.93 13.49-16.95A76 76 0 1 1 52 128a12 12 0 0 0-24 0 100 100 0 1 0 100-100Z'/%3E%3C/svg%3E");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* GitHub icon link */
|
/* GitHub icon link */
|
||||||
.header-github-link::before {
|
.header-github-link::before {
|
||||||
content: '';
|
content: '';
|
||||||
|
|
@ -126,6 +186,95 @@
|
||||||
background-color: #27272a;
|
background-color: #27272a;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mobile navbar */
|
||||||
|
@media (max-width: 996px) {
|
||||||
|
:root {
|
||||||
|
--ifm-navbar-height: 3.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar {
|
||||||
|
padding: 0 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar__logo {
|
||||||
|
margin-bottom: 0;
|
||||||
|
height: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar__logo img {
|
||||||
|
height: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hamburger menu toggle */
|
||||||
|
.navbar__toggle {
|
||||||
|
color: var(--ifm-color-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mobile sidebar */
|
||||||
|
.navbar-sidebar {
|
||||||
|
background: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-sidebar__brand {
|
||||||
|
padding: 1rem;
|
||||||
|
border-bottom: 1px solid var(--ifm-toc-border-color);
|
||||||
|
background: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-sidebar__items {
|
||||||
|
padding: 1rem 0;
|
||||||
|
background: #ffffff !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-sidebar .menu__link {
|
||||||
|
font-family: 'Space Grotesk', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 1rem;
|
||||||
|
padding: 0.75rem 1.25rem;
|
||||||
|
color: #1e293b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-sidebar .menu__link--active {
|
||||||
|
background: var(--hindsight-gradient);
|
||||||
|
-webkit-background-clip: text;
|
||||||
|
-webkit-text-fill-color: transparent;
|
||||||
|
background-clip: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close button */
|
||||||
|
.navbar-sidebar__close {
|
||||||
|
color: #1e293b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Backdrop overlay */
|
||||||
|
.navbar-sidebar__backdrop {
|
||||||
|
background: rgba(0, 0, 0, 0.5) !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dark mode mobile sidebar */
|
||||||
|
@media (max-width: 996px) {
|
||||||
|
[data-theme='dark'] .navbar-sidebar {
|
||||||
|
background: #09090b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-sidebar__brand {
|
||||||
|
background: #09090b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-sidebar__items {
|
||||||
|
background: #09090b !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-sidebar .menu__link {
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[data-theme='dark'] .navbar-sidebar__close {
|
||||||
|
color: #e2e8f0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Hero section */
|
/* Hero section */
|
||||||
.hero {
|
.hero {
|
||||||
padding: 4rem 0;
|
padding: 4rem 0;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
import ComponentTypes from '@theme-original/NavbarItem/ComponentTypes';
|
|
||||||
import NavbarIconLink from '@site/src/components/NavbarIconLink';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
...ComponentTypes,
|
|
||||||
'custom-iconLink': NavbarIconLink,
|
|
||||||
};
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
> Agent Memory that Works Like Human Memory
|
> Agent Memory that Works Like Human Memory
|
||||||
|
|
||||||
This file contains the complete Hindsight documentation for LLM consumption.
|
This file contains the complete Hindsight documentation for LLM consumption.
|
||||||
Generated: 2025-12-11T11:54:08.183Z
|
Generated: 2025-12-11T12:49:49.534Z
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -2454,27 +2454,29 @@ docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \
|
||||||
**Best for**: Production deployments, auto-scaling, cloud environments
|
**Best for**: Production deployments, auto-scaling, cloud environments
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Add Hindsight Helm repository
|
|
||||||
helm repo add hindsight https://vectorize-io.github.io/hindsight
|
|
||||||
helm repo update
|
|
||||||
|
|
||||||
# Install with built-in PostgreSQL
|
# Install with built-in PostgreSQL
|
||||||
helm install hindsight hindsight/hindsight \
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
|
||||||
--set api.llm.provider=groq \
|
--set api.llm.provider=groq \
|
||||||
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
||||||
--set postgresql.enabled=true
|
--set postgresql.enabled=true
|
||||||
|
|
||||||
# Or use external PostgreSQL
|
# Or use external PostgreSQL
|
||||||
helm install hindsight hindsight/hindsight \
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight \
|
||||||
--set api.llm.provider=groq \
|
--set api.llm.provider=groq \
|
||||||
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
--set api.llm.apiKey=gsk_xxxxxxxxxxxx \
|
||||||
--set postgresql.enabled=false \
|
--set postgresql.enabled=false \
|
||||||
--set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight
|
--set api.database.url=postgresql://user:pass@postgres.example.com:5432/hindsight
|
||||||
|
|
||||||
|
# Install a specific version
|
||||||
|
helm install hindsight oci://ghcr.io/vectorize-io/charts/hindsight --version 0.1.3
|
||||||
|
|
||||||
|
# Upgrade to latest
|
||||||
|
helm upgrade hindsight oci://ghcr.io/vectorize-io/charts/hindsight
|
||||||
```
|
```
|
||||||
|
|
||||||
**Requirements**:
|
**Requirements**:
|
||||||
- Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
|
- Kubernetes cluster (GKE, EKS, AKS, or self-hosted)
|
||||||
- Helm 3+
|
- Helm 3.8+
|
||||||
|
|
||||||
See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
|
See the [Helm chart documentation](https://github.com/vectorize-io/hindsight/tree/main/helm) for advanced configuration.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ def llm_config():
|
||||||
model = os.getenv("HINDSIGHT_LLM_MODEL", "openai/gpt-oss-120b")
|
model = os.getenv("HINDSIGHT_LLM_MODEL", "openai/gpt-oss-120b")
|
||||||
|
|
||||||
if not api_key:
|
if not api_key:
|
||||||
pytest.skip("LLM API key not configured. Set HINDSIGHT_LLM_API_KEY environment variable.")
|
raise Exception("LLM API key not configured. Set HINDSIGHT_LLM_API_KEY environment variable.")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"llm_provider": provider,
|
"llm_provider": provider,
|
||||||
|
|
|
||||||
8
uv.lock
8
uv.lock
|
|
@ -1141,7 +1141,7 @@ wheels = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hindsight-all"
|
name = "hindsight-all"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = { editable = "hindsight" }
|
source = { editable = "hindsight" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "hindsight-api" },
|
{ name = "hindsight-api" },
|
||||||
|
|
@ -1165,7 +1165,7 @@ provides-extras = ["test"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hindsight-api"
|
name = "hindsight-api"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = { editable = "hindsight-api" }
|
source = { editable = "hindsight-api" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "alembic" },
|
{ name = "alembic" },
|
||||||
|
|
@ -1265,7 +1265,7 @@ dev = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hindsight-client"
|
name = "hindsight-client"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = { editable = "hindsight-clients/python" }
|
source = { editable = "hindsight-clients/python" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiohttp" },
|
{ name = "aiohttp" },
|
||||||
|
|
@ -1297,7 +1297,7 @@ provides-extras = ["test"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hindsight-dev"
|
name = "hindsight-dev"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
source = { editable = "hindsight-dev" }
|
source = { editable = "hindsight-dev" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "hindsight-api" },
|
{ name = "hindsight-api" },
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue