fleet-memory/hindsight-integrations/litellm/hindsight_litellm/config.py
DK09876 dfccbf29f1
Added hindsight_liteLLM implementation (#17)
* Added hindsight_liteLLM implementation

* Add instructions for entity vs bank id

* Add another line about entity

* Address PR review comments and enhance litellm integration

- Remove deprecated limit parameter from recall() and arecall() functions
  since Hindsight uses budget/max_tokens for result control
- Remove dead MODEL_MAX_OUTPUT_TOKENS dict and max_output_tokens property
  from LLMProvider (superseded by hardcoded max_completion_tokens)
- Add test-litellm-integration job to CI workflow
- Add reflect API support with use_reflect config option
- Add verbose mode debug info via get_last_injection_debug()
- Add entity_id support for multi-user memory isolation
- Add retain() and reflect() wrapper functions
- Update docstrings and examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Make max_memories optional to allow unlimited memory injection

- Change max_memories default from 10 to None (no limit)
- When max_memories is None, all results from the API are used
- Fix recall result handling to properly detect list vs object return
- Update wrappers (OpenAI, Anthropic) with same optional behavior

This allows users to control memory limits via max_memory_tokens
and recall_budget without an artificial count limit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove entity_id from hindsight_litellm; add gpt-4o token cap

Multi-user support now uses separate bank_ids per user instead of
entity_id scoping (e.g., bank_id=f"user-{user_id}"). This simplifies
the API and aligns with the Hindsight architecture.

Also fixes max_completion_tokens error for gpt-4o models by capping
the value at 16384 (gpt-4o's limit) instead of sending the default
65000 which exceeds the model's supported maximum.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix dark mode styling across Control Plane UI components

Improvements to ensure proper text visibility and contrast in both light
and dark modes:

- Add global CSS rules for datetime-local calendar picker icon visibility
  using filter: invert() for both light (0.5) and dark (1) modes
- Fix text colors in dialog components to use theme-aware foreground colors
- Update memory detail panel, document/chunk modals, and data views to use
  proper dark mode text classes (text-foreground, text-card-foreground)
- Fix form labels, headings, and content text in bank selector dialogs
- Update entities view and documents view table styling for dark mode
- Bump package versions to 0.1.4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Remove session_id feature and add How It Works section to README

- Remove session_id and session management (new_session, set_session,
  get_session) from config.py, callbacks.py, and __init__.py
- Session management was a client-only abstraction not backed by core API
- Add "How It Works" section to README with visual flow diagram
- Update README to remove session management documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix readme example

* Add dark mode again

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-15 10:42:19 +01:00

232 lines
9.1 KiB
Python

"""Global configuration for Hindsight-LiteLLM integration."""
from typing import Optional, List
from dataclasses import dataclass, field
from enum import Enum
class MemoryInjectionMode(str, Enum):
"""How memories should be injected into the prompt."""
SYSTEM_MESSAGE = "system_message" # Add as system message
PREPEND_USER = "prepend_user" # Prepend to user message
DISABLED = "disabled" # Don't inject memories
@dataclass
class HindsightConfig:
"""Configuration for Hindsight integration with LiteLLM.
Attributes:
hindsight_api_url: URL of the Hindsight API server
bank_id: Memory bank ID for memory operations (required). For multi-user
support, use different bank_ids per user (e.g., f"user-{user_id}")
api_key: Optional API key for Hindsight authentication
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)
max_memories: Maximum number of memories to inject
max_memory_tokens: Maximum tokens for injected memory context
recall_budget: Budget level for memory recall (low, mid, high)
fact_types: List of fact types to filter recall (world, agent, opinion, observation)
document_id: Optional document ID for grouping stored conversations
enabled: Master switch to enable/disable Hindsight integration
excluded_models: List of model patterns to exclude from interception
verbose: Enable verbose logging
bank_name: Optional display name for the memory bank
background: Optional background/instructions for memory extraction
use_reflect: Use reflect API instead of recall for memory injection (synthesizes answer)
"""
hindsight_api_url: str = "http://localhost:8888"
bank_id: Optional[str] = None
api_key: Optional[str] = None
store_conversations: bool = True
inject_memories: bool = True
injection_mode: MemoryInjectionMode = MemoryInjectionMode.SYSTEM_MESSAGE
max_memories: Optional[int] = None # None = no limit (use all results from API)
max_memory_tokens: int = 4096
recall_budget: str = "mid" # low, mid, high
fact_types: Optional[List[str]] = None # world, agent, opinion, observation
document_id: Optional[str] = None
enabled: bool = True
excluded_models: List[str] = field(default_factory=list)
verbose: bool = False
bank_name: Optional[str] = None # Display name for the memory bank
background: Optional[str] = None # Background/instructions for memory extraction
use_reflect: bool = False # Use reflect instead of recall for memory injection
reflect_include_facts: bool = False # Include facts used by reflect in debug info
# Global configuration instance
_global_config: Optional[HindsightConfig] = None
def configure(
hindsight_api_url: str = "http://localhost:8888",
bank_id: Optional[str] = None,
api_key: Optional[str] = None,
store_conversations: bool = True,
inject_memories: bool = True,
injection_mode: MemoryInjectionMode = MemoryInjectionMode.SYSTEM_MESSAGE,
max_memories: Optional[int] = None,
max_memory_tokens: int = 4096,
recall_budget: str = "mid",
fact_types: Optional[List[str]] = None,
document_id: Optional[str] = None,
enabled: bool = True,
excluded_models: Optional[List[str]] = None,
verbose: bool = False,
bank_name: Optional[str] = None,
background: Optional[str] = None,
use_reflect: bool = False,
reflect_include_facts: bool = False,
) -> HindsightConfig:
"""Configure global Hindsight integration settings for LiteLLM.
This function sets up the global configuration that will be used by the
LiteLLM callbacks to inject memories and store conversations.
Args:
hindsight_api_url: URL of the Hindsight API server
bank_id: Memory bank ID for memory operations (required). For multi-user
support, use different bank_ids per user (e.g., f"user-{user_id}")
api_key: Optional API key for Hindsight authentication
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
max_memories: Maximum number of memories to inject
max_memory_tokens: Maximum tokens for injected memory context
recall_budget: Budget level for memory recall (low, mid, high)
fact_types: List of fact types to filter (world, agent, opinion, observation)
document_id: Optional document ID for grouping stored conversations
enabled: Master switch to enable/disable Hindsight integration
excluded_models: List of model patterns to exclude from interception
verbose: Enable verbose logging
bank_name: Optional display name for the memory bank
background: Optional background/instructions that help Hindsight understand
what information is important to extract and remember from conversations.
This is passed to create_bank() to configure the memory bank.
use_reflect: Use reflect API instead of recall for memory injection.
When True, Hindsight will synthesize a contextual answer based on
memories rather than returning raw memory facts.
reflect_include_facts: When use_reflect=True, include the facts that
were used to generate the reflect response in the debug info.
This is useful for debugging what memories the reflect API used.
Returns:
The configured HindsightConfig instance
Example:
>>> from hindsight_litellm import configure, enable
>>> configure(
... hindsight_api_url="http://localhost:8888",
... bank_id="user-123", # Per-user bank for multi-user support
... store_conversations=True,
... inject_memories=True,
... background="This agent routes customer requests to support channels. "
... "Remember which types of issues should go to which channels.",
... )
>>> enable() # Register callbacks with LiteLLM
"""
global _global_config
_global_config = HindsightConfig(
hindsight_api_url=hindsight_api_url,
bank_id=bank_id,
api_key=api_key,
store_conversations=store_conversations,
inject_memories=inject_memories,
injection_mode=injection_mode,
max_memories=max_memories,
max_memory_tokens=max_memory_tokens,
recall_budget=recall_budget,
fact_types=fact_types,
document_id=document_id,
enabled=enabled,
excluded_models=excluded_models or [],
verbose=verbose,
bank_name=bank_name,
background=background,
use_reflect=use_reflect,
reflect_include_facts=reflect_include_facts,
)
# If background or bank_name is provided, create/update the bank
if bank_id and (background or bank_name):
_create_or_update_bank(
hindsight_api_url=hindsight_api_url,
bank_id=bank_id,
name=bank_name,
background=background,
verbose=verbose,
)
return _global_config
def _create_or_update_bank(
hindsight_api_url: str,
bank_id: str,
name: Optional[str] = None,
background: Optional[str] = None,
verbose: bool = False,
) -> None:
"""Create or update a memory bank with the given configuration.
This is called automatically by configure() when background or bank_name is provided.
"""
try:
from hindsight_client import Hindsight
client = Hindsight(hindsight_api_url)
client.create_bank(
bank_id=bank_id,
name=name,
background=background,
)
if verbose:
import logging
logging.getLogger("hindsight_litellm").info(
f"Created/updated bank '{bank_id}' with background"
)
except ImportError:
if verbose:
import logging
logging.getLogger("hindsight_litellm").warning(
"hindsight_client not installed. Cannot create bank with background. "
"Install with: pip install hindsight-client"
)
except Exception as e:
if verbose:
import logging
logging.getLogger("hindsight_litellm").warning(
f"Failed to create/update bank: {e}"
)
def get_config() -> Optional[HindsightConfig]:
"""Get the current global configuration.
Returns:
The current HindsightConfig instance, or None if not configured
"""
return _global_config
def is_configured() -> bool:
"""Check if Hindsight has been configured.
Returns:
True if configure() has been called with a valid bank_id
"""
return (
_global_config is not None
and _global_config.enabled
and _global_config.bank_id is not None
)
def reset_config() -> None:
"""Reset the global configuration to None."""
global _global_config
_global_config = None