hindsight-api 0.1.8__tar.gz → 0.1.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/PKG-INFO +1 -1
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/config.py +24 -1
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/llm_wrapper.py +2 -3
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/orchestrator.py +4 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/main.py +2 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/mcp_local.py +31 -28
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/pyproject.toml +1 -1
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/.gitignore +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/README.md +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/__init__.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/README +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/env.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/script.py.mako +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/5a366d414dce_initial_schema.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/alembic/versions/rename_personality_to_disposition.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/api/__init__.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/api/http.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/api/mcp.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/banner.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/__init__.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/cross_encoder.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/db_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/embeddings.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/entity_resolver.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/memory_engine.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/query_analyzer.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/response_models.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/__init__.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/bank_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/chunk_storage.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/deduplication.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/embedding_processing.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/embedding_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/entity_processing.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/fact_extraction.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/fact_storage.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/link_creation.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/link_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/observation_regeneration.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/types.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/__init__.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/fusion.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/graph_retrieval.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/mpfp_retrieval.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/observation_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/reranking.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/retrieval.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/scoring.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/temporal_extraction.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/think_utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/trace.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/tracer.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/types.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/task_backend.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/utils.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/metrics.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/migrations.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/models.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/pg0.py +0 -0
- {hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/server.py +0 -0
|
@@ -31,6 +31,7 @@ ENV_LOG_LEVEL = "HINDSIGHT_API_LOG_LEVEL"
|
|
|
31
31
|
ENV_MCP_ENABLED = "HINDSIGHT_API_MCP_ENABLED"
|
|
32
32
|
ENV_GRAPH_RETRIEVER = "HINDSIGHT_API_GRAPH_RETRIEVER"
|
|
33
33
|
ENV_MCP_LOCAL_BANK_ID = "HINDSIGHT_API_MCP_LOCAL_BANK_ID"
|
|
34
|
+
ENV_MCP_INSTRUCTIONS = "HINDSIGHT_API_MCP_INSTRUCTIONS"
|
|
34
35
|
|
|
35
36
|
# Default values
|
|
36
37
|
DEFAULT_DATABASE_URL = "pg0"
|
|
@@ -50,6 +51,26 @@ DEFAULT_MCP_ENABLED = True
|
|
|
50
51
|
DEFAULT_GRAPH_RETRIEVER = "bfs" # Options: "bfs", "mpfp"
|
|
51
52
|
DEFAULT_MCP_LOCAL_BANK_ID = "mcp"
|
|
52
53
|
|
|
54
|
+
# Default MCP tool descriptions (can be customized via env vars)
|
|
55
|
+
DEFAULT_MCP_RETAIN_DESCRIPTION = """Store important information to long-term memory.
|
|
56
|
+
|
|
57
|
+
Use this tool PROACTIVELY whenever the user shares:
|
|
58
|
+
- Personal facts, preferences, or interests
|
|
59
|
+
- Important events or milestones
|
|
60
|
+
- User history, experiences, or background
|
|
61
|
+
- Decisions, opinions, or stated preferences
|
|
62
|
+
- Goals, plans, or future intentions
|
|
63
|
+
- Relationships or people mentioned
|
|
64
|
+
- Work context, projects, or responsibilities"""
|
|
65
|
+
|
|
66
|
+
DEFAULT_MCP_RECALL_DESCRIPTION = """Search memories to provide personalized, context-aware responses.
|
|
67
|
+
|
|
68
|
+
Use this tool PROACTIVELY to:
|
|
69
|
+
- Check user's preferences before making suggestions
|
|
70
|
+
- Recall user's history to provide continuity
|
|
71
|
+
- Remember user's goals and context
|
|
72
|
+
- Personalize responses based on past interactions"""
|
|
73
|
+
|
|
53
74
|
# Required embedding dimension for database schema
|
|
54
75
|
EMBEDDING_DIMENSION = 384
|
|
55
76
|
|
|
@@ -142,7 +163,9 @@ class HindsightConfig:
|
|
|
142
163
|
def configure_logging(self) -> None:
|
|
143
164
|
"""Configure Python logging based on the log level."""
|
|
144
165
|
logging.basicConfig(
|
|
145
|
-
level=self.get_python_log_level(),
|
|
166
|
+
level=self.get_python_log_level(),
|
|
167
|
+
format="%(asctime)s - %(levelname)s - %(name)s - %(message)s",
|
|
168
|
+
force=True, # Override any existing configuration
|
|
146
169
|
)
|
|
147
170
|
|
|
148
171
|
def log_config(self) -> None:
|
|
@@ -172,7 +172,7 @@ class LLMProvider:
|
|
|
172
172
|
|
|
173
173
|
# Check if model supports reasoning parameter (o1, o3, gpt-5 families)
|
|
174
174
|
model_lower = self.model.lower()
|
|
175
|
-
is_reasoning_model = any(x in model_lower for x in ["gpt-5", "o1", "o3"])
|
|
175
|
+
is_reasoning_model = any(x in model_lower for x in ["gpt-5", "o1", "o3", "deepseek"])
|
|
176
176
|
|
|
177
177
|
# For GPT-4 and GPT-4.1 models, cap max_completion_tokens to 32000
|
|
178
178
|
# For GPT-4o models, cap to 16384
|
|
@@ -194,7 +194,7 @@ class LLMProvider:
|
|
|
194
194
|
call_params["temperature"] = temperature
|
|
195
195
|
|
|
196
196
|
# Set reasoning_effort for reasoning models (OpenAI gpt-5, o1, o3)
|
|
197
|
-
if is_reasoning_model
|
|
197
|
+
if is_reasoning_model:
|
|
198
198
|
call_params["reasoning_effort"] = self.reasoning_effort
|
|
199
199
|
|
|
200
200
|
# Provider-specific parameters
|
|
@@ -203,7 +203,6 @@ class LLMProvider:
|
|
|
203
203
|
extra_body = {"service_tier": "auto"}
|
|
204
204
|
# Only add reasoning parameters for reasoning models
|
|
205
205
|
if is_reasoning_model:
|
|
206
|
-
extra_body["reasoning_effort"] = self.reasoning_effort
|
|
207
206
|
extra_body["include_reasoning"] = False
|
|
208
207
|
call_params["extra_body"] = extra_body
|
|
209
208
|
|
|
@@ -107,6 +107,10 @@ async def retain_batch(
|
|
|
107
107
|
)
|
|
108
108
|
|
|
109
109
|
if not extracted_facts:
|
|
110
|
+
total_time = time.time() - start_time
|
|
111
|
+
logger.info(
|
|
112
|
+
f"RETAIN_BATCH COMPLETE: 0 facts extracted from {len(contents)} contents in {total_time:.3f}s (nothing to store)"
|
|
113
|
+
)
|
|
110
114
|
return [[] for _ in contents]
|
|
111
115
|
|
|
112
116
|
# Apply fact_type_override if provided
|
|
@@ -127,8 +127,10 @@ def main():
|
|
|
127
127
|
port=args.port,
|
|
128
128
|
log_level=args.log_level,
|
|
129
129
|
mcp_enabled=config.mcp_enabled,
|
|
130
|
+
graph_retriever=config.graph_retriever,
|
|
130
131
|
)
|
|
131
132
|
config.configure_logging()
|
|
133
|
+
config.log_config()
|
|
132
134
|
|
|
133
135
|
# Register cleanup handlers
|
|
134
136
|
atexit.register(_cleanup)
|
|
@@ -28,7 +28,15 @@ Environment variables:
|
|
|
28
28
|
HINDSIGHT_API_LLM_PROVIDER: Optional. LLM provider (default: "openai").
|
|
29
29
|
HINDSIGHT_API_LLM_MODEL: Optional. LLM model (default: "gpt-4o-mini").
|
|
30
30
|
HINDSIGHT_API_MCP_LOCAL_BANK_ID: Optional. Memory bank ID (default: "mcp").
|
|
31
|
-
HINDSIGHT_API_LOG_LEVEL: Optional. Log level (default: "
|
|
31
|
+
HINDSIGHT_API_LOG_LEVEL: Optional. Log level (default: "warning").
|
|
32
|
+
HINDSIGHT_API_MCP_INSTRUCTIONS: Optional. Additional instructions appended to both retain and recall tools.
|
|
33
|
+
|
|
34
|
+
Example custom instructions (these are ADDED to the default behavior):
|
|
35
|
+
To also store assistant actions:
|
|
36
|
+
HINDSIGHT_API_MCP_INSTRUCTIONS="Also store every action you take, including tool calls, code written, and decisions made."
|
|
37
|
+
|
|
38
|
+
To also store conversation summaries:
|
|
39
|
+
HINDSIGHT_API_MCP_INSTRUCTIONS="Also store summaries of important conversations and their outcomes."
|
|
32
40
|
"""
|
|
33
41
|
|
|
34
42
|
import logging
|
|
@@ -36,14 +44,19 @@ import os
|
|
|
36
44
|
import sys
|
|
37
45
|
|
|
38
46
|
from mcp.server.fastmcp import FastMCP
|
|
47
|
+
from mcp.types import Icon
|
|
39
48
|
|
|
40
49
|
from hindsight_api.config import (
|
|
41
50
|
DEFAULT_MCP_LOCAL_BANK_ID,
|
|
51
|
+
DEFAULT_MCP_RECALL_DESCRIPTION,
|
|
52
|
+
DEFAULT_MCP_RETAIN_DESCRIPTION,
|
|
53
|
+
ENV_MCP_INSTRUCTIONS,
|
|
42
54
|
ENV_MCP_LOCAL_BANK_ID,
|
|
43
55
|
)
|
|
44
56
|
|
|
45
|
-
# Configure logging - default to
|
|
46
|
-
|
|
57
|
+
# Configure logging - default to warning to avoid polluting stderr during MCP init
|
|
58
|
+
# MCP clients interpret stderr output as errors, so we suppress INFO logs by default
|
|
59
|
+
_log_level_str = os.environ.get("HINDSIGHT_API_LOG_LEVEL", "warning").lower()
|
|
47
60
|
_log_level_map = {
|
|
48
61
|
"critical": logging.CRITICAL,
|
|
49
62
|
"error": logging.ERROR,
|
|
@@ -79,22 +92,21 @@ def create_local_mcp_server(bank_id: str, memory=None) -> FastMCP:
|
|
|
79
92
|
if memory is None:
|
|
80
93
|
memory = MemoryEngine(db_url="pg0://hindsight-mcp")
|
|
81
94
|
|
|
95
|
+
# Get custom instructions from environment variable (appended to both tools)
|
|
96
|
+
extra_instructions = os.environ.get(ENV_MCP_INSTRUCTIONS, "")
|
|
97
|
+
|
|
98
|
+
retain_description = DEFAULT_MCP_RETAIN_DESCRIPTION
|
|
99
|
+
recall_description = DEFAULT_MCP_RECALL_DESCRIPTION
|
|
100
|
+
|
|
101
|
+
if extra_instructions:
|
|
102
|
+
retain_description = f"{DEFAULT_MCP_RETAIN_DESCRIPTION}\n\nAdditional instructions: {extra_instructions}"
|
|
103
|
+
recall_description = f"{DEFAULT_MCP_RECALL_DESCRIPTION}\n\nAdditional instructions: {extra_instructions}"
|
|
104
|
+
|
|
82
105
|
mcp = FastMCP("hindsight")
|
|
83
106
|
|
|
84
|
-
@mcp.tool()
|
|
107
|
+
@mcp.tool(description=retain_description)
|
|
85
108
|
async def retain(content: str, context: str = "general") -> dict:
|
|
86
109
|
"""
|
|
87
|
-
Store important information to long-term memory.
|
|
88
|
-
|
|
89
|
-
Use this tool PROACTIVELY whenever the user shares:
|
|
90
|
-
- Personal facts, preferences, or interests
|
|
91
|
-
- Important events or milestones
|
|
92
|
-
- User history, experiences, or background
|
|
93
|
-
- Decisions, opinions, or stated preferences
|
|
94
|
-
- Goals, plans, or future intentions
|
|
95
|
-
- Relationships or people mentioned
|
|
96
|
-
- Work context, projects, or responsibilities
|
|
97
|
-
|
|
98
110
|
Args:
|
|
99
111
|
content: The fact/memory to store (be specific and include relevant details)
|
|
100
112
|
context: Category for the memory (e.g., 'preferences', 'work', 'hobbies', 'family'). Default: 'general'
|
|
@@ -111,17 +123,9 @@ def create_local_mcp_server(bank_id: str, memory=None) -> FastMCP:
|
|
|
111
123
|
asyncio.create_task(_retain())
|
|
112
124
|
return {"status": "accepted", "message": "Memory storage initiated"}
|
|
113
125
|
|
|
114
|
-
@mcp.tool()
|
|
126
|
+
@mcp.tool(description=recall_description)
|
|
115
127
|
async def recall(query: str, max_tokens: int = 4096, budget: str = "low") -> dict:
|
|
116
128
|
"""
|
|
117
|
-
Search memories to provide personalized, context-aware responses.
|
|
118
|
-
|
|
119
|
-
Use this tool PROACTIVELY to:
|
|
120
|
-
- Check user's preferences before making suggestions
|
|
121
|
-
- Recall user's history to provide continuity
|
|
122
|
-
- Remember user's goals and context
|
|
123
|
-
- Personalize responses based on past interactions
|
|
124
|
-
|
|
125
129
|
Args:
|
|
126
130
|
query: Natural language search query (e.g., "user's food preferences", "what projects is user working on")
|
|
127
131
|
max_tokens: Maximum tokens to return in results (default: 4096)
|
|
@@ -153,10 +157,9 @@ async def _initialize_and_run(bank_id: str):
|
|
|
153
157
|
from hindsight_api import MemoryEngine
|
|
154
158
|
|
|
155
159
|
# Create and initialize memory engine with pg0 embedded database
|
|
156
|
-
|
|
160
|
+
# Note: We avoid printing to stderr during init as MCP clients show it as "errors"
|
|
157
161
|
memory = MemoryEngine(db_url="pg0://hindsight-mcp")
|
|
158
162
|
await memory.initialize()
|
|
159
|
-
print("Memory engine initialized.", file=sys.stderr)
|
|
160
163
|
|
|
161
164
|
# Create and run the server
|
|
162
165
|
mcp = create_local_mcp_server(bank_id, memory=memory)
|
|
@@ -179,8 +182,8 @@ def main():
|
|
|
179
182
|
# Get bank ID from environment, default to "mcp"
|
|
180
183
|
bank_id = os.environ.get(ENV_MCP_LOCAL_BANK_ID, DEFAULT_MCP_LOCAL_BANK_ID)
|
|
181
184
|
|
|
182
|
-
#
|
|
183
|
-
|
|
185
|
+
# Note: We don't print to stderr as MCP clients display it as "error output"
|
|
186
|
+
# Use HINDSIGHT_API_LOG_LEVEL=debug for verbose startup logging
|
|
184
187
|
|
|
185
188
|
# Run the async initialization and server
|
|
186
189
|
asyncio.run(_initialize_and_run(bank_id))
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/embedding_processing.py
RENAMED
|
File without changes
|
|
File without changes
|
{hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/entity_processing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/retain/observation_regeneration.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/observation_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{hindsight_api-0.1.8 → hindsight_api-0.1.9}/hindsight_api/engine/search/temporal_extraction.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|