diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 321b78db..17a5dd1e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -219,6 +219,9 @@ jobs: release-helm-chart: runs-on: ubuntu-latest + permissions: + contents: read + packages: write steps: - uses: actions/checkout@v4 @@ -228,12 +231,18 @@ jobs: with: 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 run: helm lint helm/hindsight - name: Package Helm chart 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 uses: actions/upload-artifact@v4 with: diff --git a/README.md b/README.md index 8a62e856..3812db73 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ UI: http://localhost:9999 Install client: ```bash -pip install hindsight-client +pip install hindsight-client -U # or 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) ```bash -pip install hindsight-all +pip install hindsight-all -U ``` ```python @@ -100,27 +100,27 @@ from hindsight import HindsightServer, HindsightClient with HindsightServer( llm_provider="openai", - llm_model="gpt-4o-mini", + llm_model="gpt-5-mini", llm_api_key=os.environ["OPENAI_API_KEY"] ) as server: client = HindsightClient(base_url=server.url) - client.retain(bank_id="my-agent", content="Alice works at Google") - results = client.recall(bank_id="my-agent", query="Where does Alice work?") + client.retain(bank_id="my-bank", content="Alice works at Google") + results = client.recall(bank_id="my-bank", query="Where does Alice work?") ``` -### TypeScript +### Node.js / TypeScript ```bash npm install @vectorize-io/hindsight-client ``` -```typescript -import { HindsightClient } from '@vectorize-io/hindsight-client'; +```javascript +const { HindsightClient } = require('@vectorize-io/hindsight-client'); const client = new HindsightClient({ baseUrl: 'http://localhost:8888' }); -await client.retain('my-agent', 'Alice loves hiking in Yosemite'); -const response = await client.recall('my-agent', 'What does Alice like?'); +await client.retain('my-bank', 'Alice loves hiking in Yosemite'); +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?") # 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: diff --git a/docker/standalone/Dockerfile b/docker/standalone/Dockerfile index 4b83f536..bff75095 100644 --- a/docker/standalone/Dockerfile +++ b/docker/standalone/Dockerfile @@ -177,6 +177,7 @@ ENV HINDSIGHT_API_PORT=8888 ENV HINDSIGHT_API_LOG_LEVEL=info ENV HINDSIGHT_ENABLE_API=true ENV HINDSIGHT_ENABLE_CP=false +ENV PYTHONUNBUFFERED=1 CMD ["/app/start-all.sh"] @@ -311,6 +312,7 @@ ENV NODE_ENV=production ENV HINDSIGHT_CP_DATAPLANE_API_URL=http://localhost:8888 ENV HINDSIGHT_ENABLE_API=true ENV HINDSIGHT_ENABLE_CP=true +ENV PYTHONUNBUFFERED=1 CMD ["/app/start-all.sh"] diff --git a/docker/standalone/start-all.sh b/docker/standalone/start-all.sh index 4e3a4267..b7fcda8b 100755 --- a/docker/standalone/start-all.sh +++ b/docker/standalone/start-all.sh @@ -23,7 +23,7 @@ PIDS=() # Start API if enabled if [ "$ENABLE_API" = "true" ]; then cd /app/api - hindsight-api 2>&1 | sed 's/^/[api] /' & + hindsight-api 2>&1 | sed -u 's/^/[api] /' & API_PID=$! PIDS+=($API_PID) @@ -42,7 +42,7 @@ fi if [ "$ENABLE_CP" = "true" ]; then echo "🎛️ Starting 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=$! PIDS+=($CP_PID) else diff --git a/hindsight-api/hindsight_api/engine/llm_wrapper.py b/hindsight-api/hindsight_api/engine/llm_wrapper.py index 6710f0f0..5bbeee25 100644 --- a/hindsight-api/hindsight_api/engine/llm_wrapper.py +++ b/hindsight-api/hindsight_api/engine/llm_wrapper.py @@ -170,24 +170,38 @@ class LLMProvider: "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) model_lower = self.model.lower() 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) if temperature is not None and not is_reasoning_model: 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 if self.provider == "groq": call_params["seed"] = DEFAULT_LLM_SEED - call_params["extra_body"] = { - "service_tier": "auto", - "reasoning_effort": self.reasoning_effort, - "include_reasoning": False, - } + extra_body = {"service_tier": "auto"} + # Only add reasoning parameters for reasoning models + if is_reasoning_model: + extra_body["reasoning_effort"] = self.reasoning_effort + extra_body["include_reasoning"] = False + call_params["extra_body"] = extra_body last_exception = None diff --git a/hindsight-api/tests/test_llm_provider.py b/hindsight-api/tests/test_llm_provider.py index 65433878..7f48c60b 100644 --- a/hindsight-api/tests/test_llm_provider.py +++ b/hindsight-api/tests/test_llm_provider.py @@ -10,36 +10,30 @@ from hindsight_api.engine.llm_wrapper import LLMProvider MODEL_MATRIX = [ # OpenAI models ("openai", "gpt-4o-mini"), + ("openai", "gpt-4.1-mini"), + ("openai", "gpt-4.1-nano"), ("openai", "gpt-5-mini"), + ("openai", "gpt-5-nano"), + ("openai", "gpt-5"), # Groq models ("groq", "llama-3.3-70b-versatile"), ("groq", "openai/gpt-oss-120b"), + ("groq", "openai/gpt-oss-20b"), # Gemini models - ("gemini", "gemini-2.0-flash"), - ("gemini", "gemini-2.5-flash-preview-05-20"), + ("gemini", "gemini-2.5-flash"), + ("gemini", "gemini-2.5-flash-lite"), ] def get_api_key_for_provider(provider: str) -> str | None: """Get API key for provider from environment variables.""" - # Try provider-specific env vars first provider_key_map = { - "openai": ["OPENAI_API_KEY", "HINDSIGHT_API_LLM_API_KEY"], - "groq": ["GROQ_API_KEY", "HINDSIGHT_API_LLM_API_KEY"], - "gemini": ["GEMINI_API_KEY", "GOOGLE_API_KEY", "HINDSIGHT_API_LLM_API_KEY"], + "openai": "OPENAI_API_KEY", + "groq": "GROQ_API_KEY", + "gemini": "GEMINI_API_KEY", } - - for env_var in provider_key_map.get(provider, []): - 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 + env_var = provider_key_map.get(provider) + return os.getenv(env_var) if env_var else None @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) LARGE_OUTPUT_MODELS = [ ("openai", "gpt-5-mini"), - ("gemini", "gemini-2.0-flash"), - ("gemini", "gemini-2.5-flash-preview-05-20"), + ("openai", "gpt-5-nano"), + ("openai", "gpt-5"), + ("gemini", "gemini-2.5-flash"), + ("gemini", "gemini-2.5-flash-lite"), ] diff --git a/hindsight-clients/python/hindsight_client/__init__.py b/hindsight-clients/python/hindsight_client/__init__.py index e4c80f88..da26080e 100644 --- a/hindsight-clients/python/hindsight_client/__init__.py +++ b/hindsight-clients/python/hindsight_client/__init__.py @@ -15,8 +15,8 @@ Example: print(result.success) # Search memories - results = client.recall(bank_id="alice", query="What does Alice like?") - for r in results: + response = client.recall(bank_id="alice", query="What does Alice like?") + for r in response.results: print(r.text) # Generate contextual answer @@ -29,14 +29,59 @@ from .hindsight_client import Hindsight # Re-export response types for convenient access from hindsight_client_api.models.retain_response import RetainResponse -from hindsight_client_api.models.recall_response import RecallResponse -from hindsight_client_api.models.recall_result import RecallResult +from hindsight_client_api.models.recall_response import RecallResponse as _RecallResponse +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_fact import ReflectFact 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.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__ = [ "Hindsight", # Response types diff --git a/hindsight-clients/python/hindsight_client/hindsight_client.py b/hindsight-clients/python/hindsight_client/hindsight_client.py index b3a9a7f7..87f7c7fa 100644 --- a/hindsight-clients/python/hindsight_client/hindsight_client.py +++ b/hindsight-clients/python/hindsight_client/hindsight_client.py @@ -50,7 +50,9 @@ class Hindsight: client.retain(bank_id="alice", content="Alice loves AI") # 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 answer = client.reflect(bank_id="alice", query="What are my interests?") @@ -125,8 +127,8 @@ class Hindsight: Args: bank_id: The memory bank ID - items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata' - document_id: Optional document ID for grouping memories + items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id' + 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) Returns: @@ -138,13 +140,14 @@ class Hindsight: timestamp=item.get("timestamp"), context=item.get("context"), metadata=item.get("metadata"), + # Use item's document_id if provided, otherwise fall back to batch-level document_id + document_id=item.get("document_id") or document_id, ) for item in items ] request_obj = retain_request.RetainRequest( items=memory_items, - document_id=document_id, async_=retain_async, ) @@ -161,6 +164,8 @@ class Hindsight: query_timestamp: Optional[str] = None, include_entities: bool = False, max_entity_tokens: int = 500, + include_chunks: bool = False, + max_chunk_tokens: int = 8192, ) -> RecallResponse: """ 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') include_entities: Include entity observations in results (default: False) 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: - 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( - 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( @@ -277,8 +285,8 @@ class Hindsight: Args: bank_id: The memory bank ID - items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata' - document_id: Optional document ID for grouping memories + items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id' + 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) Returns: @@ -290,13 +298,14 @@ class Hindsight: timestamp=item.get("timestamp"), context=item.get("context"), metadata=item.get("metadata"), + # Use item's document_id if provided, otherwise fall back to batch-level document_id + document_id=item.get("document_id") or document_id, ) for item in items ] request_obj = retain_request.RetainRequest( items=memory_items, - document_id=document_id, async_=retain_async, ) diff --git a/hindsight-clients/typescript/src/index.ts b/hindsight-clients/typescript/src/index.ts index fcd7b873..db08c7be 100644 --- a/hindsight-clients/typescript/src/index.ts +++ b/hindsight-clients/typescript/src/index.ts @@ -128,7 +128,17 @@ export class HindsightClient { async recall( bankId: 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 { const response = await sdk.recallMemories({ client: this.client, @@ -139,6 +149,11 @@ export class HindsightClient { max_tokens: options?.maxTokens, budget: options?.budget || 'mid', 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, + }, }, }); diff --git a/hindsight-docs/docs/developer/api/think-vs-search.md b/hindsight-docs/docs/developer/api/think-vs-search.md deleted file mode 100644 index 9a6baf03..00000000 --- a/hindsight-docs/docs/developer/api/think-vs-search.md +++ /dev/null @@ -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 diff --git a/hindsight-docs/docs/developer/installation.md b/hindsight-docs/docs/developer/installation.md index 0d922b19..58e05992 100644 --- a/hindsight-docs/docs/developer/installation.md +++ b/hindsight-docs/docs/developer/installation.md @@ -55,27 +55,29 @@ docker run --rm -it --pull always -p 8888:8888 -p 9999:9999 \ **Best for**: Production deployments, auto-scaling, cloud environments ```bash -# Add Hindsight Helm repository -helm repo add hindsight https://vectorize-io.github.io/hindsight -helm repo update - # 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.apiKey=gsk_xxxxxxxxxxxx \ --set postgresql.enabled=true # 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.apiKey=gsk_xxxxxxxxxxxx \ --set postgresql.enabled=false \ --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**: - 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. diff --git a/hindsight-docs/docs/sdks/nodejs.md b/hindsight-docs/docs/sdks/nodejs.md index d25dbe96..e2406c09 100644 --- a/hindsight-docs/docs/sdks/nodejs.md +++ b/hindsight-docs/docs/sdks/nodejs.md @@ -15,21 +15,21 @@ npm install @vectorize-io/hindsight-client ## Quick Start ```typescript -import { HindsightClient } from '@vectorize-io/hindsight-client'; +const { HindsightClient } = require('@vectorize-io/hindsight-client'); const client = new HindsightClient({ baseUrl: 'http://localhost:8888' }); // Retain a memory -await client.retain('my-agent', 'Alice works at Google'); +await client.retain('my-bank', 'Alice works at Google'); // 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) { console.log(r.text); } // 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); ``` @@ -49,10 +49,10 @@ const client = new HindsightClient({ ```typescript // Simple -await client.retain('my-agent', 'Alice works at Google'); +await client.retain('my-bank', 'Alice works at Google'); // With options -await client.retain('my-agent', 'Alice got promoted', { +await client.retain('my-bank', 'Alice got promoted', { timestamp: new Date('2024-01-15'), context: 'career update', metadata: { source: 'slack' }, @@ -63,11 +63,10 @@ await client.retain('my-agent', 'Alice got promoted', { ### Retain Batch ```typescript -await client.retainBatch('my-agent', [ +await client.retainBatch('my-bank', [ { content: 'Alice works at Google', context: 'career' }, { content: 'Bob is a data scientist', context: 'career' }, ], { - documentId: 'conversation_001', async: false, }); ``` @@ -76,31 +75,29 @@ await client.retainBatch('my-agent', [ ```typescript // 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) { console.log(`${r.text} (type: ${r.type})`); } // 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 maxTokens: 4096, budget: 'high', // 'low', 'mid', or 'high' - trace: true, }); ``` ### Reflect (Generate Response) ```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' context: 'preparing for a meeting', }); console.log(answer.text); // Generated response -console.log(answer.based_on); // Memories used ``` ## Bank Management @@ -108,7 +105,7 @@ console.log(answer.based_on); // Memories used ### Create Bank ```typescript -await client.createBank('my-agent', { +await client.createBank('my-bank', { name: 'Assistant', background: 'I am a helpful AI assistant', 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 ```typescript -const response = await client.listMemories('my-agent', { +const response = await client.listMemories('my-bank', { type: 'world', // Optional filter q: 'Alice', // Optional text search limit: 100, offset: 0, }); - -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); +console.log(response) ``` diff --git a/hindsight-docs/docs/sdks/python.md b/hindsight-docs/docs/sdks/python.md index ad311c69..d746dd78 100644 --- a/hindsight-docs/docs/sdks/python.md +++ b/hindsight-docs/docs/sdks/python.md @@ -49,15 +49,15 @@ with HindsightServer( client = HindsightClient(base_url=server.url) # 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 - 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: print(r.text) # 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) ``` @@ -70,15 +70,15 @@ from hindsight_client import Hindsight client = Hindsight(base_url="http://localhost:8888") # 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 -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: print(r.text) # 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) ``` @@ -103,7 +103,7 @@ client = Hindsight( ```python # Simple client.retain( - bank_id="my-agent", + bank_id="my-bank", content="Alice works at Google as a software engineer", ) @@ -111,7 +111,7 @@ client.retain( from datetime import datetime client.retain( - bank_id="my-agent", + bank_id="my-bank", content="Alice got promoted", context="career update", timestamp=datetime(2024, 1, 15), @@ -124,7 +124,7 @@ client.retain( ```python client.retain_batch( - bank_id="my-agent", + bank_id="my-bank", items=[ {"content": "Alice works at Google", "context": "career"}, {"content": "Bob is a data scientist", "context": "career"}, @@ -139,16 +139,16 @@ client.retain_batch( ```python # Simple - returns list of RecallResult results = client.recall( - bank_id="my-agent", + bank_id="my-bank", query="What does Alice do?", ) -for r in results: +for r in results.results: print(f"{r.text} (type: {r.type})") # With options results = client.recall( - bank_id="my-agent", + bank_id="my-bank", query="What does Alice do?", types=["world", "opinion"], # Filter by fact type max_tokens=4096, @@ -159,16 +159,15 @@ results = client.recall( ### Recall with Full Response ```python -# Returns RecallResponse with entities and trace info -response = client.recall_memories( - bank_id="my-agent", +# Returns RecallResponse with entities and chunks +response = client.recall( + bank_id="my-bank", query="What does Alice do?", types=["world", "experience"], budget="mid", max_tokens=4096, - trace=True, include_entities=True, - max_entity_tokens=500, + max_entity_tokens=500 ) print(f"Found {len(response.results)} memories") @@ -185,14 +184,13 @@ if response.entities: ```python answer = client.reflect( - bank_id="my-agent", + bank_id="my-bank", query="What should I know about Alice?", budget="low", # low, mid, or high context="preparing for a meeting", ) print(answer.text) # Generated response -print(answer.based_on) # Memories used ``` ## Bank Management @@ -201,7 +199,7 @@ print(answer.based_on) # Memories used ```python client.create_bank( - bank_id="my-agent", + bank_id="my-bank", name="Assistant", background="I am a helpful AI assistant", disposition={ @@ -215,16 +213,13 @@ client.create_bank( ### List Memories ```python -response = client.list_memories( - bank_id="my-agent", +client.list_memories( + bank_id="my-bank", type="world", # Optional: filter by type search_query="Alice", # Optional: text search limit=100, offset=0, ) - -for memory in response.memories: - print(f"{memory.id}: {memory.text}") ``` ## Async Support @@ -239,15 +234,15 @@ async def main(): client = Hindsight(base_url="http://localhost:8888") # Async retain - await client.aretain(bank_id="my-agent", content="Hello world") + await client.aretain(bank_id="my-bank", content="Hello world") # 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: print(r.text) # 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) client.close() @@ -255,29 +250,13 @@ async def 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 ```python from hindsight_client import Hindsight with Hindsight(base_url="http://localhost:8888") as client: - client.retain(bank_id="my-agent", content="Hello") - results = client.recall(bank_id="my-agent", query="Hello") + client.retain(bank_id="my-bank", content="Hello") + results = client.recall(bank_id="my-bank", query="Hello") # Client automatically closed ``` diff --git a/hindsight-docs/docusaurus.config.ts b/hindsight-docs/docusaurus.config.ts index 63fa0403..85ddd091 100644 --- a/hindsight-docs/docusaurus.config.ts +++ b/hindsight-docs/docusaurus.config.ts @@ -128,39 +128,38 @@ const config: Config = { }, items: [ { - type: 'custom-iconLink', + type: 'doc', + docId: 'developer/index', position: 'left', - icon: 'code', label: 'Developer', - to: '/', + className: 'navbar-item-developer', }, { - type: 'custom-iconLink', + type: 'doc', + docId: 'sdks/python', position: 'left', - icon: 'package', label: 'SDKs', - to: '/sdks/python', + className: 'navbar-item-sdks', }, { - type: 'custom-iconLink', - position: 'left', - icon: 'file-code', - label: 'API Reference', to: '/api-reference', + position: 'left', + label: 'API Reference', + className: 'navbar-item-api', }, { - type: 'custom-iconLink', + type: 'doc', + docId: 'cookbook/index', position: 'left', - icon: 'book-open', label: 'Cookbook', - to: '/cookbook', + className: 'navbar-item-cookbook', }, { - type: 'custom-iconLink', + type: 'doc', + docId: 'changelog/index', position: 'left', - icon: 'clock', label: 'Changelog', - to: '/changelog', + className: 'navbar-item-changelog', }, { 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: { theme: prismThemes.github, diff --git a/hindsight-docs/package-lock.json b/hindsight-docs/package-lock.json index f916dc09..0211405d 100644 --- a/hindsight-docs/package-lock.json +++ b/hindsight-docs/package-lock.json @@ -13,7 +13,6 @@ "@docusaurus/theme-common": "^3.9.2", "@docusaurus/theme-mermaid": "^3.9.2", "@mdx-js/react": "^3.0.0", - "@phosphor-icons/react": "^2.1.10", "clsx": "^2.0.0", "prism-react-renderer": "^2.3.0", "react": "^19.0.0", @@ -4534,19 +4533,6 @@ "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": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", diff --git a/hindsight-docs/package.json b/hindsight-docs/package.json index 63e6b4ff..cdccc1b0 100644 --- a/hindsight-docs/package.json +++ b/hindsight-docs/package.json @@ -21,7 +21,6 @@ "@docusaurus/theme-common": "^3.9.2", "@docusaurus/theme-mermaid": "^3.9.2", "@mdx-js/react": "^3.0.0", - "@phosphor-icons/react": "^2.1.10", "clsx": "^2.0.0", "prism-react-renderer": "^2.3.0", "react": "^19.0.0", diff --git a/hindsight-docs/src/components/NavbarIconLink.tsx b/hindsight-docs/src/components/NavbarIconLink.tsx deleted file mode 100644 index 98d4ed71..00000000 --- a/hindsight-docs/src/components/NavbarIconLink.tsx +++ /dev/null @@ -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 ( - - {IconComponent && ( - - )} - {label} - - ); -} diff --git a/hindsight-docs/src/css/custom.css b/hindsight-docs/src/css/custom.css index 896a55df..b1cf7324 100644 --- a/hindsight-docs/src/css/custom.css +++ b/hindsight-docs/src/css/custom.css @@ -94,6 +94,66 @@ 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 */ .header-github-link::before { content: ''; @@ -126,6 +186,95 @@ 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 { padding: 4rem 0; diff --git a/hindsight-docs/src/theme/NavbarItem/ComponentTypes.tsx b/hindsight-docs/src/theme/NavbarItem/ComponentTypes.tsx deleted file mode 100644 index 8d2d7d26..00000000 --- a/hindsight-docs/src/theme/NavbarItem/ComponentTypes.tsx +++ /dev/null @@ -1,7 +0,0 @@ -import ComponentTypes from '@theme-original/NavbarItem/ComponentTypes'; -import NavbarIconLink from '@site/src/components/NavbarIconLink'; - -export default { - ...ComponentTypes, - 'custom-iconLink': NavbarIconLink, -}; diff --git a/hindsight-docs/static/llms-full.txt b/hindsight-docs/static/llms-full.txt index 6e0a68ac..a11d2ab3 100644 --- a/hindsight-docs/static/llms-full.txt +++ b/hindsight-docs/static/llms-full.txt @@ -3,7 +3,7 @@ > Agent Memory that Works Like Human Memory 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 ```bash -# Add Hindsight Helm repository -helm repo add hindsight https://vectorize-io.github.io/hindsight -helm repo update - # 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.apiKey=gsk_xxxxxxxxxxxx \ --set postgresql.enabled=true # 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.apiKey=gsk_xxxxxxxxxxxx \ --set postgresql.enabled=false \ --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**: - 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. diff --git a/hindsight/tests/test_server_integration.py b/hindsight/tests/test_server_integration.py index 1b1258a1..fe755923 100644 --- a/hindsight/tests/test_server_integration.py +++ b/hindsight/tests/test_server_integration.py @@ -27,7 +27,7 @@ def llm_config(): model = os.getenv("HINDSIGHT_LLM_MODEL", "openai/gpt-oss-120b") 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 { "llm_provider": provider, diff --git a/uv.lock b/uv.lock index bfe57a23..4d7f5678 100644 --- a/uv.lock +++ b/uv.lock @@ -1141,7 +1141,7 @@ wheels = [ [[package]] name = "hindsight-all" -version = "0.1.2" +version = "0.1.3" source = { editable = "hindsight" } dependencies = [ { name = "hindsight-api" }, @@ -1165,7 +1165,7 @@ provides-extras = ["test"] [[package]] name = "hindsight-api" -version = "0.1.2" +version = "0.1.3" source = { editable = "hindsight-api" } dependencies = [ { name = "alembic" }, @@ -1265,7 +1265,7 @@ dev = [ [[package]] name = "hindsight-client" -version = "0.1.2" +version = "0.1.3" source = { editable = "hindsight-clients/python" } dependencies = [ { name = "aiohttp" }, @@ -1297,7 +1297,7 @@ provides-extras = ["test"] [[package]] name = "hindsight-dev" -version = "0.1.2" +version = "0.1.3" source = { editable = "hindsight-dev" } dependencies = [ { name = "hindsight-api" },