Compare commits
4
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
24cccd7c69 | ||
|
|
d4d646218e | ||
|
|
ef6db8365c | ||
|
|
654c1a4488 |
@@ -324,7 +324,7 @@ class Hindsight:
|
||||
self,
|
||||
bank_id: str,
|
||||
name: str | None = None,
|
||||
background: str | None = None,
|
||||
mission: str | None = None,
|
||||
disposition: dict[str, float] | None = None,
|
||||
) -> BankProfileResponse:
|
||||
"""Create or update a memory bank.
|
||||
|
||||
@@ -15,10 +15,16 @@ This module provides a clean API for configuring Hindsight integration:
|
||||
4. set_bank_mission() - Set the mission for a memory bank (for mental models)
|
||||
"""
|
||||
|
||||
import os
|
||||
from typing import Optional, List, Any, Dict
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
|
||||
# Default Hindsight API URL (production)
|
||||
DEFAULT_HINDSIGHT_API_URL = "https://api.hindsight.vectorize.io"
|
||||
DEFAULT_BANK_ID = "default"
|
||||
HINDSIGHT_API_KEY_ENV = "HINDSIGHT_API_KEY"
|
||||
|
||||
|
||||
class MemoryInjectionMode(str, Enum):
|
||||
"""How memories should be injected into the prompt.
|
||||
@@ -37,7 +43,11 @@ class HindsightConfig:
|
||||
|
||||
Attributes:
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
api_key: Optional API key for Hindsight authentication
|
||||
(default: https://api.hindsight.vectorize.io)
|
||||
bank_id: Memory bank ID for memory operations (default: "default").
|
||||
For multi-user support, use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
api_key: API key for Hindsight authentication. If not provided,
|
||||
reads from HINDSIGHT_API_KEY environment variable.
|
||||
store_conversations: Whether to store conversations to Hindsight
|
||||
inject_memories: Whether to inject relevant memories into prompts
|
||||
injection_mode: How to inject memories (system_message or prepend_user)
|
||||
@@ -47,7 +57,8 @@ class HindsightConfig:
|
||||
If False (default), storage runs in background thread for better performance.
|
||||
"""
|
||||
|
||||
hindsight_api_url: str = "http://localhost:8888"
|
||||
hindsight_api_url: str = DEFAULT_HINDSIGHT_API_URL
|
||||
bank_id: str = DEFAULT_BANK_ID
|
||||
api_key: Optional[str] = None
|
||||
store_conversations: bool = True
|
||||
inject_memories: bool = True
|
||||
@@ -102,8 +113,11 @@ _global_defaults: Optional[HindsightDefaults] = None
|
||||
|
||||
|
||||
def configure(
|
||||
hindsight_api_url: str = "http://localhost:8888",
|
||||
hindsight_api_url: Optional[str] = None,
|
||||
bank_id: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
background: Optional[str] = None,
|
||||
bank_name: Optional[str] = None,
|
||||
store_conversations: bool = True,
|
||||
inject_memories: bool = True,
|
||||
injection_mode: MemoryInjectionMode = MemoryInjectionMode.SYSTEM_MESSAGE,
|
||||
@@ -116,9 +130,20 @@ def configure(
|
||||
This sets up settings that typically don't change during a session.
|
||||
For per-call settings like bank_id, use set_defaults() or per-call kwargs.
|
||||
|
||||
With sensible defaults, you can use minimal configuration:
|
||||
|
||||
configure() # Just set HINDSIGHT_API_KEY env var
|
||||
enable()
|
||||
|
||||
Args:
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
api_key: Optional API key for Hindsight authentication
|
||||
(default: https://api.hindsight.vectorize.io)
|
||||
bank_id: Memory bank ID for memory operations (default: "default").
|
||||
For multi-user support, use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
api_key: API key for Hindsight authentication. If not provided,
|
||||
reads from HINDSIGHT_API_KEY environment variable.
|
||||
background: Instructions guiding what Hindsight should learn and remember.
|
||||
bank_name: Optional display name for the bank.
|
||||
store_conversations: Whether to store conversations to Hindsight
|
||||
inject_memories: Whether to inject relevant memories into prompts
|
||||
injection_mode: How to inject memories into the prompt
|
||||
@@ -132,20 +157,30 @@ def configure(
|
||||
The configured HindsightConfig instance
|
||||
|
||||
Example:
|
||||
>>> from hindsight_litellm import configure, set_defaults, enable
|
||||
>>> from hindsight_litellm import configure, enable
|
||||
>>>
|
||||
>>> # Minimal usage - just set HINDSIGHT_API_KEY env var
|
||||
>>> configure()
|
||||
>>> enable()
|
||||
>>>
|
||||
>>> # Or with custom settings
|
||||
>>> configure(
|
||||
... hindsight_api_url="http://localhost:8888",
|
||||
... api_key="your-api-key",
|
||||
... verbose=True,
|
||||
... bank_id="user-123", # Per-user bank for multi-user support
|
||||
... background="Remember user preferences and past interactions.",
|
||||
... )
|
||||
>>> set_defaults(bank_id="user-123")
|
||||
>>> enable() # Start memory integration
|
||||
>>> enable()
|
||||
"""
|
||||
global _global_config
|
||||
|
||||
# Apply defaults
|
||||
resolved_api_url = hindsight_api_url or DEFAULT_HINDSIGHT_API_URL
|
||||
resolved_bank_id = bank_id or DEFAULT_BANK_ID
|
||||
resolved_api_key = api_key or os.environ.get(HINDSIGHT_API_KEY_ENV)
|
||||
|
||||
_global_config = HindsightConfig(
|
||||
hindsight_api_url=hindsight_api_url,
|
||||
api_key=api_key,
|
||||
hindsight_api_url=resolved_api_url,
|
||||
bank_id=resolved_bank_id,
|
||||
api_key=resolved_api_key,
|
||||
store_conversations=store_conversations,
|
||||
inject_memories=inject_memories,
|
||||
injection_mode=injection_mode,
|
||||
@@ -154,6 +189,17 @@ def configure(
|
||||
sync_storage=sync_storage,
|
||||
)
|
||||
|
||||
# If background or bank_name is provided, create/update the bank
|
||||
if background or bank_name:
|
||||
_create_or_update_bank(
|
||||
hindsight_api_url=resolved_api_url,
|
||||
bank_id=resolved_bank_id,
|
||||
name=bank_name,
|
||||
mission=background,
|
||||
verbose=verbose,
|
||||
api_key=resolved_api_key,
|
||||
)
|
||||
|
||||
return _global_config
|
||||
|
||||
|
||||
@@ -244,6 +290,7 @@ def _create_or_update_bank(
|
||||
name: Optional[str] = None,
|
||||
mission: Optional[str] = None,
|
||||
verbose: bool = False,
|
||||
api_key: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Create or update a memory bank with the given configuration.
|
||||
|
||||
@@ -257,7 +304,7 @@ def _create_or_update_bank(
|
||||
try:
|
||||
from hindsight_client import Hindsight
|
||||
|
||||
client = Hindsight(hindsight_api_url)
|
||||
client = Hindsight(base_url=hindsight_api_url, api_key=api_key)
|
||||
client.create_bank(
|
||||
bank_id=bank_id,
|
||||
name=name,
|
||||
@@ -305,8 +352,10 @@ def is_configured() -> bool:
|
||||
"""Check if Hindsight has been configured with a valid bank_id.
|
||||
|
||||
Returns:
|
||||
True if configure() has been called and a bank_id is set in defaults
|
||||
True if configure() has been called and a bank_id is set
|
||||
"""
|
||||
if _global_config is not None and _global_config.bank_id:
|
||||
return True
|
||||
return (
|
||||
_global_config is not None
|
||||
and _global_defaults is not None
|
||||
|
||||
@@ -8,10 +8,16 @@ integration with native client libraries.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
from typing import Any, Dict, List, Optional, Union
|
||||
from dataclasses import dataclass
|
||||
|
||||
# Default Hindsight API URL (production)
|
||||
DEFAULT_HINDSIGHT_API_URL = "https://api.hindsight.vectorize.io"
|
||||
DEFAULT_BANK_ID = "default"
|
||||
HINDSIGHT_API_KEY_ENV = "HINDSIGHT_API_KEY"
|
||||
|
||||
from .config import get_config, get_defaults, is_configured, HindsightConfig
|
||||
|
||||
|
||||
@@ -22,7 +28,7 @@ _retain_errors_lock = threading.Lock()
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _get_client(api_url: str):
|
||||
def _get_client(api_url: str, api_key: Optional[str] = None):
|
||||
"""Create a fresh Hindsight client for the given URL.
|
||||
|
||||
Note: We create a fresh client each time because the hindsight_client
|
||||
@@ -30,7 +36,7 @@ def _get_client(api_url: str):
|
||||
calls causes asyncio context issues.
|
||||
"""
|
||||
from hindsight_client import Hindsight
|
||||
return Hindsight(base_url=api_url, timeout=30.0)
|
||||
return Hindsight(base_url=api_url, api_key=api_key, timeout=30.0)
|
||||
|
||||
|
||||
def _close_client():
|
||||
@@ -145,7 +151,7 @@ def recall(
|
||||
client = None
|
||||
try:
|
||||
# Create fresh client for this operation
|
||||
client = _get_client(api_url)
|
||||
client = _get_client(api_url, config.api_key if config else None)
|
||||
|
||||
# Call recall API
|
||||
results = client.recall(
|
||||
@@ -308,7 +314,7 @@ def reflect(
|
||||
client = None
|
||||
try:
|
||||
# Create fresh client for this operation
|
||||
client = _get_client(api_url)
|
||||
client = _get_client(api_url, config.api_key if config else None)
|
||||
|
||||
# Call reflect API
|
||||
reflect_kwargs = {
|
||||
@@ -410,12 +416,13 @@ def _retain_sync(
|
||||
target_document_id: Optional[str],
|
||||
metadata: Optional[Dict[str, str]],
|
||||
verbose: bool,
|
||||
api_key: Optional[str] = None,
|
||||
) -> RetainResult:
|
||||
"""Internal synchronous retain implementation."""
|
||||
client = None
|
||||
try:
|
||||
# Create fresh client for this operation
|
||||
client = _get_client(api_url)
|
||||
client = _get_client(api_url, api_key)
|
||||
|
||||
# Call retain API
|
||||
result = client.retain(
|
||||
@@ -467,6 +474,7 @@ def _retain_background(
|
||||
target_document_id: Optional[str],
|
||||
metadata: Optional[Dict[str, str]],
|
||||
verbose: bool,
|
||||
api_key: Optional[str] = None,
|
||||
) -> None:
|
||||
"""Background thread worker for async retain."""
|
||||
global _retain_errors
|
||||
@@ -479,6 +487,7 @@ def _retain_background(
|
||||
target_document_id=target_document_id,
|
||||
metadata=metadata,
|
||||
verbose=verbose,
|
||||
api_key=api_key,
|
||||
)
|
||||
except Exception as e:
|
||||
with _retain_errors_lock:
|
||||
@@ -571,6 +580,8 @@ def retain(
|
||||
"Hindsight not configured. Call configure() or provide bank_id and hindsight_api_url."
|
||||
)
|
||||
|
||||
api_key = config.api_key if config else None
|
||||
|
||||
if sync:
|
||||
# Synchronous mode - block and return result
|
||||
return _retain_sync(
|
||||
@@ -581,6 +592,7 @@ def retain(
|
||||
target_document_id=target_document_id,
|
||||
metadata=metadata,
|
||||
verbose=verbose,
|
||||
api_key=api_key,
|
||||
)
|
||||
else:
|
||||
# Async mode - run in background thread
|
||||
@@ -594,6 +606,7 @@ def retain(
|
||||
target_document_id,
|
||||
metadata,
|
||||
verbose,
|
||||
api_key,
|
||||
),
|
||||
daemon=True,
|
||||
)
|
||||
@@ -653,6 +666,7 @@ class HindsightOpenAI:
|
||||
client: Any,
|
||||
bank_id: str,
|
||||
hindsight_api_url: str = "http://localhost:8888",
|
||||
api_key: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
store_conversations: bool = True,
|
||||
inject_memories: bool = True,
|
||||
@@ -667,6 +681,7 @@ class HindsightOpenAI:
|
||||
bank_id: Memory bank ID for memory operations. For multi-user support,
|
||||
use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
api_key: Optional API key for Hindsight authentication
|
||||
session_id: Session identifier for conversation grouping
|
||||
store_conversations: Whether to store conversations
|
||||
inject_memories: Whether to inject relevant memories
|
||||
@@ -677,6 +692,7 @@ class HindsightOpenAI:
|
||||
self._client = client
|
||||
self._bank_id = bank_id
|
||||
self._api_url = hindsight_api_url
|
||||
self._api_key = api_key
|
||||
self._session_id = session_id
|
||||
self._store_conversations = store_conversations
|
||||
self._inject_memories = inject_memories
|
||||
@@ -694,6 +710,7 @@ class HindsightOpenAI:
|
||||
from hindsight_client import Hindsight
|
||||
self._hindsight_client = Hindsight(
|
||||
base_url=self._api_url,
|
||||
api_key=self._api_key,
|
||||
timeout=30.0,
|
||||
)
|
||||
return self._hindsight_client
|
||||
@@ -857,6 +874,7 @@ class HindsightAnthropic:
|
||||
client: Any,
|
||||
bank_id: str,
|
||||
hindsight_api_url: str = "http://localhost:8888",
|
||||
api_key: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
store_conversations: bool = True,
|
||||
inject_memories: bool = True,
|
||||
@@ -871,6 +889,7 @@ class HindsightAnthropic:
|
||||
bank_id: Memory bank ID for memory operations. For multi-user support,
|
||||
use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
api_key: Optional API key for Hindsight authentication
|
||||
session_id: Session identifier for conversation grouping
|
||||
store_conversations: Whether to store conversations
|
||||
inject_memories: Whether to inject relevant memories
|
||||
@@ -881,6 +900,7 @@ class HindsightAnthropic:
|
||||
self._client = client
|
||||
self._bank_id = bank_id
|
||||
self._api_url = hindsight_api_url
|
||||
self._api_key = api_key
|
||||
self._session_id = session_id
|
||||
self._store_conversations = store_conversations
|
||||
self._inject_memories = inject_memories
|
||||
@@ -898,6 +918,7 @@ class HindsightAnthropic:
|
||||
from hindsight_client import Hindsight
|
||||
self._hindsight_client = Hindsight(
|
||||
base_url=self._api_url,
|
||||
api_key=self._api_key,
|
||||
timeout=30.0,
|
||||
)
|
||||
return self._hindsight_client
|
||||
@@ -1031,8 +1052,9 @@ class _WrappedAnthropicMessages:
|
||||
|
||||
def wrap_openai(
|
||||
client: Any,
|
||||
bank_id: str,
|
||||
hindsight_api_url: str = "http://localhost:8888",
|
||||
bank_id: Optional[str] = None,
|
||||
hindsight_api_url: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
store_conversations: bool = True,
|
||||
inject_memories: bool = True,
|
||||
@@ -1045,14 +1067,23 @@ def wrap_openai(
|
||||
This creates a wrapped client that automatically injects memories
|
||||
and stores conversations when making chat completion calls.
|
||||
|
||||
With sensible defaults, you can use it with minimal configuration:
|
||||
|
||||
client = wrap_openai(OpenAI())
|
||||
|
||||
Just set the HINDSIGHT_API_KEY environment variable and you're ready to go.
|
||||
|
||||
Args:
|
||||
client: The OpenAI client instance to wrap
|
||||
bank_id: Memory bank ID for memory operations. For multi-user support,
|
||||
bank_id: Memory bank ID (default: "default"). For multi-user support,
|
||||
use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
(default: https://api.hindsight.vectorize.io)
|
||||
api_key: API key for Hindsight authentication. If not provided,
|
||||
reads from HINDSIGHT_API_KEY environment variable.
|
||||
session_id: Session identifier for conversation grouping
|
||||
store_conversations: Whether to store conversations
|
||||
inject_memories: Whether to inject relevant memories
|
||||
store_conversations: Whether to store conversations (default: True)
|
||||
inject_memories: Whether to inject relevant memories (default: True)
|
||||
max_memories: Maximum number of memories to inject (None = no limit)
|
||||
budget: Budget level for memory recall (low, mid, high)
|
||||
verbose: Enable verbose logging
|
||||
@@ -1064,21 +1095,24 @@ def wrap_openai(
|
||||
>>> from openai import OpenAI
|
||||
>>> from hindsight_litellm import wrap_openai
|
||||
>>>
|
||||
>>> client = OpenAI()
|
||||
>>> wrapped = wrap_openai(
|
||||
... client,
|
||||
... bank_id=f"user-{user_id}", # Multi-user support via separate banks
|
||||
... )
|
||||
>>> # Minimal usage - just set HINDSIGHT_API_KEY env var
|
||||
>>> client = wrap_openai(OpenAI())
|
||||
>>>
|
||||
>>> response = wrapped.chat.completions.create(
|
||||
... model="gpt-4",
|
||||
>>> response = client.chat.completions.create(
|
||||
... model="gpt-4o-mini",
|
||||
... messages=[{"role": "user", "content": "What do you know about me?"}]
|
||||
... )
|
||||
"""
|
||||
# Apply defaults
|
||||
resolved_bank_id = bank_id or DEFAULT_BANK_ID
|
||||
resolved_api_url = hindsight_api_url or DEFAULT_HINDSIGHT_API_URL
|
||||
resolved_api_key = api_key or os.environ.get(HINDSIGHT_API_KEY_ENV)
|
||||
|
||||
return HindsightOpenAI(
|
||||
client=client,
|
||||
bank_id=bank_id,
|
||||
hindsight_api_url=hindsight_api_url,
|
||||
bank_id=resolved_bank_id,
|
||||
hindsight_api_url=resolved_api_url,
|
||||
api_key=resolved_api_key,
|
||||
session_id=session_id,
|
||||
store_conversations=store_conversations,
|
||||
inject_memories=inject_memories,
|
||||
@@ -1090,8 +1124,9 @@ def wrap_openai(
|
||||
|
||||
def wrap_anthropic(
|
||||
client: Any,
|
||||
bank_id: str,
|
||||
hindsight_api_url: str = "http://localhost:8888",
|
||||
bank_id: Optional[str] = None,
|
||||
hindsight_api_url: Optional[str] = None,
|
||||
api_key: Optional[str] = None,
|
||||
session_id: Optional[str] = None,
|
||||
store_conversations: bool = True,
|
||||
inject_memories: bool = True,
|
||||
@@ -1104,14 +1139,23 @@ def wrap_anthropic(
|
||||
This creates a wrapped client that automatically injects memories
|
||||
and stores conversations when making message calls.
|
||||
|
||||
With sensible defaults, you can use it with minimal configuration:
|
||||
|
||||
client = wrap_anthropic(Anthropic())
|
||||
|
||||
Just set the HINDSIGHT_API_KEY environment variable and you're ready to go.
|
||||
|
||||
Args:
|
||||
client: The Anthropic client instance to wrap
|
||||
bank_id: Memory bank ID for memory operations. For multi-user support,
|
||||
bank_id: Memory bank ID (default: "default"). For multi-user support,
|
||||
use different bank_ids per user (e.g., f"user-{user_id}")
|
||||
hindsight_api_url: URL of the Hindsight API server
|
||||
(default: https://api.hindsight.vectorize.io)
|
||||
api_key: API key for Hindsight authentication. If not provided,
|
||||
reads from HINDSIGHT_API_KEY environment variable.
|
||||
session_id: Session identifier for conversation grouping
|
||||
store_conversations: Whether to store conversations
|
||||
inject_memories: Whether to inject relevant memories
|
||||
store_conversations: Whether to store conversations (default: True)
|
||||
inject_memories: Whether to inject relevant memories (default: True)
|
||||
max_memories: Maximum number of memories to inject (None = no limit)
|
||||
budget: Budget level for memory recall (low, mid, high)
|
||||
verbose: Enable verbose logging
|
||||
@@ -1123,22 +1167,25 @@ def wrap_anthropic(
|
||||
>>> from anthropic import Anthropic
|
||||
>>> from hindsight_litellm import wrap_anthropic
|
||||
>>>
|
||||
>>> client = Anthropic()
|
||||
>>> wrapped = wrap_anthropic(
|
||||
... client,
|
||||
... bank_id=f"user-{user_id}", # Multi-user support via separate banks
|
||||
... )
|
||||
>>> # Minimal usage - just set HINDSIGHT_API_KEY env var
|
||||
>>> client = wrap_anthropic(Anthropic())
|
||||
>>>
|
||||
>>> response = wrapped.messages.create(
|
||||
... model="claude-3-5-sonnet-20241022",
|
||||
>>> response = client.messages.create(
|
||||
... model="claude-sonnet-4-20250514",
|
||||
... max_tokens=1024,
|
||||
... messages=[{"role": "user", "content": "What do you know about me?"}]
|
||||
... )
|
||||
"""
|
||||
# Apply defaults
|
||||
resolved_bank_id = bank_id or DEFAULT_BANK_ID
|
||||
resolved_api_url = hindsight_api_url or DEFAULT_HINDSIGHT_API_URL
|
||||
resolved_api_key = api_key or os.environ.get(HINDSIGHT_API_KEY_ENV)
|
||||
|
||||
return HindsightAnthropic(
|
||||
client=client,
|
||||
bank_id=bank_id,
|
||||
hindsight_api_url=hindsight_api_url,
|
||||
bank_id=resolved_bank_id,
|
||||
hindsight_api_url=resolved_api_url,
|
||||
api_key=resolved_api_key,
|
||||
session_id=session_id,
|
||||
store_conversations=store_conversations,
|
||||
inject_memories=inject_memories,
|
||||
|
||||
@@ -61,3 +61,8 @@ packages = ["hindsight_litellm"]
|
||||
[tool.pytest.ini_options]
|
||||
asyncio_mode = "auto"
|
||||
testpaths = ["tests"]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"pytest>=9.0.2",
|
||||
]
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
"""Unit tests for hindsight_litellm configuration and defaults."""
|
||||
|
||||
import os
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from hindsight_litellm import configure, wrap_openai, wrap_anthropic, reset_config, is_configured
|
||||
from hindsight_litellm.config import (
|
||||
DEFAULT_HINDSIGHT_API_URL,
|
||||
DEFAULT_BANK_ID,
|
||||
HINDSIGHT_API_KEY_ENV,
|
||||
reset_config,
|
||||
get_config,
|
||||
is_configured,
|
||||
)
|
||||
from hindsight_litellm.wrappers import HindsightOpenAI, HindsightAnthropic
|
||||
|
||||
|
||||
class TestDefaults:
|
||||
"""Test default configuration values."""
|
||||
|
||||
def test_default_api_url(self):
|
||||
"""Test default API URL is production."""
|
||||
assert DEFAULT_HINDSIGHT_API_URL == "https://api.hindsight.vectorize.io"
|
||||
|
||||
def test_default_bank_id(self):
|
||||
"""Test default bank ID is 'default'."""
|
||||
assert DEFAULT_BANK_ID == "default"
|
||||
|
||||
def test_env_var_name(self):
|
||||
"""Test environment variable name for API key."""
|
||||
assert HINDSIGHT_API_KEY_ENV == "HINDSIGHT_API_KEY"
|
||||
|
||||
|
||||
class TestConfigure:
|
||||
"""Test configure() function."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Reset config before each test."""
|
||||
reset_config()
|
||||
|
||||
def teardown_method(self):
|
||||
"""Reset config after each test."""
|
||||
reset_config()
|
||||
|
||||
def test_configure_with_no_arguments(self):
|
||||
"""Test configure() with no arguments uses defaults."""
|
||||
config = configure()
|
||||
|
||||
assert config.hindsight_api_url == DEFAULT_HINDSIGHT_API_URL
|
||||
assert config.bank_id == DEFAULT_BANK_ID
|
||||
|
||||
def test_configure_reads_api_key_from_env(self):
|
||||
"""Test configure() reads API key from environment variable."""
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "test-api-key-123"}):
|
||||
config = configure()
|
||||
|
||||
assert config.api_key == "test-api-key-123"
|
||||
|
||||
def test_configure_explicit_api_key_overrides_env(self):
|
||||
"""Test explicit api_key parameter overrides environment variable."""
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "env-key"}):
|
||||
config = configure(api_key="explicit-key")
|
||||
|
||||
assert config.api_key == "explicit-key"
|
||||
|
||||
def test_configure_explicit_values_override_defaults(self):
|
||||
"""Test explicit values override defaults."""
|
||||
config = configure(
|
||||
hindsight_api_url="http://custom-url:8888",
|
||||
bank_id="custom-bank",
|
||||
api_key="custom-key",
|
||||
)
|
||||
|
||||
assert config.hindsight_api_url == "http://custom-url:8888"
|
||||
assert config.bank_id == "custom-bank"
|
||||
assert config.api_key == "custom-key"
|
||||
|
||||
def test_is_configured_true_with_defaults(self):
|
||||
"""Test is_configured() returns True with default config."""
|
||||
configure()
|
||||
assert is_configured() is True
|
||||
|
||||
def test_is_configured_false_when_not_configured(self):
|
||||
"""Test is_configured() returns False when not configured."""
|
||||
reset_config()
|
||||
assert is_configured() is False
|
||||
|
||||
|
||||
class TestWrapOpenAI:
|
||||
"""Test wrap_openai() function."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Reset config before each test."""
|
||||
reset_config()
|
||||
|
||||
def teardown_method(self):
|
||||
"""Reset config after each test."""
|
||||
reset_config()
|
||||
|
||||
def test_wrap_openai_with_only_client(self):
|
||||
"""Test wrap_openai() works with only the client argument."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "test-key"}):
|
||||
wrapped = wrap_openai(mock_client)
|
||||
|
||||
assert isinstance(wrapped, HindsightOpenAI)
|
||||
assert wrapped._bank_id == DEFAULT_BANK_ID
|
||||
assert wrapped._api_url == DEFAULT_HINDSIGHT_API_URL
|
||||
assert wrapped._api_key == "test-key"
|
||||
|
||||
def test_wrap_openai_uses_defaults(self):
|
||||
"""Test wrap_openai() uses default values."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
wrapped = wrap_openai(mock_client)
|
||||
|
||||
assert wrapped._bank_id == DEFAULT_BANK_ID
|
||||
assert wrapped._api_url == DEFAULT_HINDSIGHT_API_URL
|
||||
|
||||
def test_wrap_openai_reads_api_key_from_env(self):
|
||||
"""Test wrap_openai() reads API key from environment."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "env-api-key"}):
|
||||
wrapped = wrap_openai(mock_client)
|
||||
|
||||
assert wrapped._api_key == "env-api-key"
|
||||
|
||||
def test_wrap_openai_explicit_overrides_defaults(self):
|
||||
"""Test wrap_openai() explicit values override defaults."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
wrapped = wrap_openai(
|
||||
mock_client,
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:9999",
|
||||
api_key="my-key",
|
||||
)
|
||||
|
||||
assert wrapped._bank_id == "my-bank"
|
||||
assert wrapped._api_url == "http://localhost:9999"
|
||||
assert wrapped._api_key == "my-key"
|
||||
|
||||
|
||||
class TestWrapAnthropic:
|
||||
"""Test wrap_anthropic() function."""
|
||||
|
||||
def setup_method(self):
|
||||
"""Reset config before each test."""
|
||||
reset_config()
|
||||
|
||||
def teardown_method(self):
|
||||
"""Reset config after each test."""
|
||||
reset_config()
|
||||
|
||||
def test_wrap_anthropic_with_only_client(self):
|
||||
"""Test wrap_anthropic() works with only the client argument."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "test-key"}):
|
||||
wrapped = wrap_anthropic(mock_client)
|
||||
|
||||
assert isinstance(wrapped, HindsightAnthropic)
|
||||
assert wrapped._bank_id == DEFAULT_BANK_ID
|
||||
assert wrapped._api_url == DEFAULT_HINDSIGHT_API_URL
|
||||
assert wrapped._api_key == "test-key"
|
||||
|
||||
def test_wrap_anthropic_uses_defaults(self):
|
||||
"""Test wrap_anthropic() uses default values."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
wrapped = wrap_anthropic(mock_client)
|
||||
|
||||
assert wrapped._bank_id == DEFAULT_BANK_ID
|
||||
assert wrapped._api_url == DEFAULT_HINDSIGHT_API_URL
|
||||
|
||||
def test_wrap_anthropic_reads_api_key_from_env(self):
|
||||
"""Test wrap_anthropic() reads API key from environment."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
with patch.dict(os.environ, {HINDSIGHT_API_KEY_ENV: "env-api-key"}):
|
||||
wrapped = wrap_anthropic(mock_client)
|
||||
|
||||
assert wrapped._api_key == "env-api-key"
|
||||
|
||||
def test_wrap_anthropic_explicit_overrides_defaults(self):
|
||||
"""Test wrap_anthropic() explicit values override defaults."""
|
||||
mock_client = MagicMock()
|
||||
|
||||
wrapped = wrap_anthropic(
|
||||
mock_client,
|
||||
bank_id="my-bank",
|
||||
hindsight_api_url="http://localhost:9999",
|
||||
api_key="my-key",
|
||||
)
|
||||
|
||||
assert wrapped._bank_id == "my-bank"
|
||||
assert wrapped._api_url == "http://localhost:9999"
|
||||
assert wrapped._api_key == "my-key"
|
||||
@@ -85,17 +85,22 @@ class TestConfiguration:
|
||||
assert defaults.fact_types == ["world", "opinion"]
|
||||
assert defaults.document_id == "doc-123"
|
||||
|
||||
def test_is_configured_without_bank_id(self):
|
||||
"""Test is_configured returns False without bank_id."""
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
assert is_configured() is False
|
||||
def test_is_configured_with_defaults(self):
|
||||
"""Test is_configured returns True with default bank_id."""
|
||||
configure() # Uses default bank_id="default"
|
||||
assert is_configured() is True
|
||||
|
||||
def test_is_configured_with_bank_id(self):
|
||||
"""Test is_configured returns True with bank_id."""
|
||||
def test_is_configured_with_bank_id_in_defaults(self):
|
||||
"""Test is_configured returns True with bank_id in defaults."""
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
set_defaults(bank_id="test-agent")
|
||||
assert is_configured() is True
|
||||
|
||||
def test_is_configured_with_explicit_bank_id(self):
|
||||
"""Test is_configured returns True with explicit bank_id."""
|
||||
configure(bank_id="test-agent")
|
||||
assert is_configured() is True
|
||||
|
||||
def test_reset_config(self):
|
||||
"""Test reset_config clears the configuration."""
|
||||
configure(hindsight_api_url="http://localhost:8888")
|
||||
|
||||
Generated
+8
@@ -707,6 +707,11 @@ dev = [
|
||||
{ name = "pytest-mock" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "aiohttp", specifier = ">=3.13.3" },
|
||||
@@ -719,6 +724,9 @@ requires-dist = [
|
||||
]
|
||||
provides-extras = ["dev"]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [{ name = "pytest", specifier = ">=9.0.2" }]
|
||||
|
||||
[[package]]
|
||||
name = "httpcore"
|
||||
version = "1.0.9"
|
||||
|
||||
Reference in New Issue
Block a user