hindsight-api 0.2.1__py3-none-any.whl → 0.4.0__py3-none-any.whl

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.
Files changed (88) hide show
  1. hindsight_api/admin/__init__.py +1 -0
  2. hindsight_api/admin/cli.py +311 -0
  3. hindsight_api/alembic/versions/f1a2b3c4d5e6_add_memory_links_composite_index.py +44 -0
  4. hindsight_api/alembic/versions/g2a3b4c5d6e7_add_tags_column.py +48 -0
  5. hindsight_api/alembic/versions/h3c4d5e6f7g8_mental_models_v4.py +112 -0
  6. hindsight_api/alembic/versions/i4d5e6f7g8h9_delete_opinions.py +41 -0
  7. hindsight_api/alembic/versions/j5e6f7g8h9i0_mental_model_versions.py +95 -0
  8. hindsight_api/alembic/versions/k6f7g8h9i0j1_add_directive_subtype.py +58 -0
  9. hindsight_api/alembic/versions/l7g8h9i0j1k2_add_worker_columns.py +109 -0
  10. hindsight_api/alembic/versions/m8h9i0j1k2l3_mental_model_id_to_text.py +41 -0
  11. hindsight_api/alembic/versions/n9i0j1k2l3m4_learnings_and_pinned_reflections.py +134 -0
  12. hindsight_api/alembic/versions/o0j1k2l3m4n5_migrate_mental_models_data.py +113 -0
  13. hindsight_api/alembic/versions/p1k2l3m4n5o6_new_knowledge_architecture.py +194 -0
  14. hindsight_api/alembic/versions/q2l3m4n5o6p7_fix_mental_model_fact_type.py +50 -0
  15. hindsight_api/alembic/versions/r3m4n5o6p7q8_add_reflect_response_to_reflections.py +47 -0
  16. hindsight_api/alembic/versions/s4n5o6p7q8r9_add_consolidated_at_to_memory_units.py +53 -0
  17. hindsight_api/alembic/versions/t5o6p7q8r9s0_rename_mental_models_to_observations.py +134 -0
  18. hindsight_api/alembic/versions/u6p7q8r9s0t1_mental_models_text_id.py +41 -0
  19. hindsight_api/alembic/versions/v7q8r9s0t1u2_add_max_tokens_to_mental_models.py +50 -0
  20. hindsight_api/api/http.py +1406 -118
  21. hindsight_api/api/mcp.py +11 -196
  22. hindsight_api/config.py +359 -27
  23. hindsight_api/engine/consolidation/__init__.py +5 -0
  24. hindsight_api/engine/consolidation/consolidator.py +859 -0
  25. hindsight_api/engine/consolidation/prompts.py +69 -0
  26. hindsight_api/engine/cross_encoder.py +706 -88
  27. hindsight_api/engine/db_budget.py +284 -0
  28. hindsight_api/engine/db_utils.py +11 -0
  29. hindsight_api/engine/directives/__init__.py +5 -0
  30. hindsight_api/engine/directives/models.py +37 -0
  31. hindsight_api/engine/embeddings.py +553 -29
  32. hindsight_api/engine/entity_resolver.py +8 -5
  33. hindsight_api/engine/interface.py +40 -17
  34. hindsight_api/engine/llm_wrapper.py +744 -68
  35. hindsight_api/engine/memory_engine.py +2505 -1017
  36. hindsight_api/engine/mental_models/__init__.py +14 -0
  37. hindsight_api/engine/mental_models/models.py +53 -0
  38. hindsight_api/engine/query_analyzer.py +4 -3
  39. hindsight_api/engine/reflect/__init__.py +18 -0
  40. hindsight_api/engine/reflect/agent.py +933 -0
  41. hindsight_api/engine/reflect/models.py +109 -0
  42. hindsight_api/engine/reflect/observations.py +186 -0
  43. hindsight_api/engine/reflect/prompts.py +483 -0
  44. hindsight_api/engine/reflect/tools.py +437 -0
  45. hindsight_api/engine/reflect/tools_schema.py +250 -0
  46. hindsight_api/engine/response_models.py +168 -4
  47. hindsight_api/engine/retain/bank_utils.py +79 -201
  48. hindsight_api/engine/retain/fact_extraction.py +424 -195
  49. hindsight_api/engine/retain/fact_storage.py +35 -12
  50. hindsight_api/engine/retain/link_utils.py +29 -24
  51. hindsight_api/engine/retain/orchestrator.py +24 -43
  52. hindsight_api/engine/retain/types.py +11 -2
  53. hindsight_api/engine/search/graph_retrieval.py +43 -14
  54. hindsight_api/engine/search/link_expansion_retrieval.py +391 -0
  55. hindsight_api/engine/search/mpfp_retrieval.py +362 -117
  56. hindsight_api/engine/search/reranking.py +2 -2
  57. hindsight_api/engine/search/retrieval.py +848 -201
  58. hindsight_api/engine/search/tags.py +172 -0
  59. hindsight_api/engine/search/think_utils.py +42 -141
  60. hindsight_api/engine/search/trace.py +12 -1
  61. hindsight_api/engine/search/tracer.py +26 -6
  62. hindsight_api/engine/search/types.py +21 -3
  63. hindsight_api/engine/task_backend.py +113 -106
  64. hindsight_api/engine/utils.py +1 -152
  65. hindsight_api/extensions/__init__.py +10 -1
  66. hindsight_api/extensions/builtin/tenant.py +5 -1
  67. hindsight_api/extensions/context.py +10 -1
  68. hindsight_api/extensions/operation_validator.py +81 -4
  69. hindsight_api/extensions/tenant.py +26 -0
  70. hindsight_api/main.py +69 -6
  71. hindsight_api/mcp_local.py +12 -53
  72. hindsight_api/mcp_tools.py +494 -0
  73. hindsight_api/metrics.py +433 -48
  74. hindsight_api/migrations.py +141 -1
  75. hindsight_api/models.py +3 -3
  76. hindsight_api/pg0.py +53 -0
  77. hindsight_api/server.py +39 -2
  78. hindsight_api/worker/__init__.py +11 -0
  79. hindsight_api/worker/main.py +296 -0
  80. hindsight_api/worker/poller.py +486 -0
  81. {hindsight_api-0.2.1.dist-info → hindsight_api-0.4.0.dist-info}/METADATA +16 -6
  82. hindsight_api-0.4.0.dist-info/RECORD +112 -0
  83. {hindsight_api-0.2.1.dist-info → hindsight_api-0.4.0.dist-info}/entry_points.txt +2 -0
  84. hindsight_api/engine/retain/observation_regeneration.py +0 -254
  85. hindsight_api/engine/search/observation_utils.py +0 -125
  86. hindsight_api/engine/search/scoring.py +0 -159
  87. hindsight_api-0.2.1.dist-info/RECORD +0 -75
  88. {hindsight_api-0.2.1.dist-info → hindsight_api-0.4.0.dist-info}/WHEEL +0 -0
hindsight_api/api/mcp.py CHANGED
@@ -1,4 +1,4 @@
1
- """Hindsight MCP Server implementation using FastMCP."""
1
+ """Hindsight MCP Server implementation using FastMCP (HTTP transport)."""
2
2
 
3
3
  import json
4
4
  import logging
@@ -8,9 +8,7 @@ from contextvars import ContextVar
8
8
  from fastmcp import FastMCP
9
9
 
10
10
  from hindsight_api import MemoryEngine
11
- from hindsight_api.api.http import BankListItem, BankListResponse, BankProfileResponse, DispositionTraits
12
- from hindsight_api.engine.response_models import VALID_RECALL_FACT_TYPES
13
- from hindsight_api.models import RequestContext
11
+ from hindsight_api.mcp_tools import MCPToolsConfig, register_mcp_tools
14
12
 
15
13
  # Configure logging from HINDSIGHT_API_LOG_LEVEL environment variable
16
14
  _log_level_str = os.environ.get("HINDSIGHT_API_LOG_LEVEL", "info").lower()
@@ -53,198 +51,15 @@ def create_mcp_server(memory: MemoryEngine) -> FastMCP:
53
51
  # Use stateless_http=True for Claude Code compatibility
54
52
  mcp = FastMCP("hindsight-mcp-server", stateless_http=True)
55
53
 
56
- @mcp.tool()
57
- async def retain(content: str, context: str = "general", bank_id: str | None = None) -> str:
58
- """
59
- Store important information to long-term memory.
60
-
61
- Use this tool PROACTIVELY whenever the user shares:
62
- - Personal facts, preferences, or interests
63
- - Important events or milestones
64
- - User history, experiences, or background
65
- - Decisions, opinions, or stated preferences
66
- - Goals, plans, or future intentions
67
- - Relationships or people mentioned
68
- - Work context, projects, or responsibilities
69
-
70
- Args:
71
- content: The fact/memory to store (be specific and include relevant details)
72
- context: Category for the memory (e.g., 'preferences', 'work', 'hobbies', 'family'). Default: 'general'
73
- bank_id: Optional bank to store in (defaults to session bank). Use for cross-bank operations.
74
- """
75
- try:
76
- target_bank = bank_id or get_current_bank_id()
77
- if target_bank is None:
78
- return "Error: No bank_id configured"
79
- await memory.retain_batch_async(
80
- bank_id=target_bank,
81
- contents=[{"content": content, "context": context}],
82
- request_context=RequestContext(),
83
- )
84
- return f"Memory stored successfully in bank '{target_bank}'"
85
- except Exception as e:
86
- logger.error(f"Error storing memory: {e}", exc_info=True)
87
- return f"Error: {str(e)}"
88
-
89
- @mcp.tool()
90
- async def recall(query: str, max_tokens: int = 4096, bank_id: str | None = None) -> str:
91
- """
92
- Search memories to provide personalized, context-aware responses.
93
-
94
- Use this tool PROACTIVELY to:
95
- - Check user's preferences before making suggestions
96
- - Recall user's history to provide continuity
97
- - Remember user's goals and context
98
- - Personalize responses based on past interactions
99
-
100
- Args:
101
- query: Natural language search query (e.g., "user's food preferences", "what projects is user working on")
102
- max_tokens: Maximum tokens in the response (default: 4096)
103
- bank_id: Optional bank to search in (defaults to session bank). Use for cross-bank operations.
104
- """
105
- try:
106
- target_bank = bank_id or get_current_bank_id()
107
- if target_bank is None:
108
- return "Error: No bank_id configured"
109
- from hindsight_api.engine.memory_engine import Budget
110
-
111
- recall_result = await memory.recall_async(
112
- bank_id=target_bank,
113
- query=query,
114
- fact_type=list(VALID_RECALL_FACT_TYPES),
115
- budget=Budget.HIGH,
116
- max_tokens=max_tokens,
117
- request_context=RequestContext(),
118
- )
119
-
120
- # Use model's JSON serialization
121
- return recall_result.model_dump_json(indent=2)
122
- except Exception as e:
123
- logger.error(f"Error searching: {e}", exc_info=True)
124
- return f'{{"error": "{e}", "results": []}}'
125
-
126
- @mcp.tool()
127
- async def reflect(query: str, context: str | None = None, budget: str = "low", bank_id: str | None = None) -> str:
128
- """
129
- Generate thoughtful analysis by synthesizing stored memories with the bank's personality.
130
-
131
- WHEN TO USE THIS TOOL:
132
- Use reflect when you need reasoned analysis, not just fact retrieval. This tool
133
- thinks through the question using everything the bank knows and its personality traits.
134
-
135
- EXAMPLES OF GOOD QUERIES:
136
- - "What patterns have emerged in how I approach debugging?"
137
- - "Based on my past decisions, what architectural style do I prefer?"
138
- - "What might be the best approach for this problem given what you know about me?"
139
- - "How should I prioritize these tasks based on my goals?"
140
-
141
- HOW IT DIFFERS FROM RECALL:
142
- - recall: Returns raw facts matching your search (fast lookup)
143
- - reflect: Reasons across memories to form a synthesized answer (deeper analysis)
144
-
145
- Use recall for "what did I say about X?" and reflect for "what should I do about X?"
146
-
147
- Args:
148
- query: The question or topic to reflect on
149
- context: Optional context about why this reflection is needed
150
- budget: Search budget - 'low', 'mid', or 'high' (default: 'low')
151
- bank_id: Optional bank to reflect in (defaults to session bank). Use for cross-bank operations.
152
- """
153
- try:
154
- target_bank = bank_id or get_current_bank_id()
155
- if target_bank is None:
156
- return "Error: No bank_id configured"
157
- from hindsight_api.engine.memory_engine import Budget
158
-
159
- # Map string budget to enum
160
- budget_map = {"low": Budget.LOW, "mid": Budget.MID, "high": Budget.HIGH}
161
- budget_enum = budget_map.get(budget.lower(), Budget.LOW)
162
-
163
- reflect_result = await memory.reflect_async(
164
- bank_id=target_bank,
165
- query=query,
166
- budget=budget_enum,
167
- context=context,
168
- request_context=RequestContext(),
169
- )
170
-
171
- return reflect_result.model_dump_json(indent=2)
172
- except Exception as e:
173
- logger.error(f"Error reflecting: {e}", exc_info=True)
174
- return f'{{"error": "{e}", "text": ""}}'
175
-
176
- @mcp.tool()
177
- async def list_banks() -> str:
178
- """
179
- List all available memory banks.
180
-
181
- Use this to discover banks for orchestration or to find
182
- the correct bank_id for cross-bank operations.
183
-
184
- Returns:
185
- JSON object with banks array containing bank_id, name, disposition, background, and timestamps
186
- """
187
- try:
188
- banks = await memory.list_banks(request_context=RequestContext())
189
- bank_items = [
190
- BankListItem(
191
- bank_id=b.get("bank_id") or b.get("id"),
192
- name=b.get("name"),
193
- disposition=DispositionTraits(
194
- **b.get("disposition", {"skepticism": 3, "literalism": 3, "empathy": 3})
195
- ),
196
- background=b.get("background"),
197
- created_at=str(b.get("created_at")) if b.get("created_at") else None,
198
- updated_at=str(b.get("updated_at")) if b.get("updated_at") else None,
199
- )
200
- for b in banks
201
- ]
202
- return BankListResponse(banks=bank_items).model_dump_json(indent=2)
203
- except Exception as e:
204
- logger.error(f"Error listing banks: {e}", exc_info=True)
205
- return f'{{"error": "{e}", "banks": []}}'
206
-
207
- @mcp.tool()
208
- async def create_bank(bank_id: str, name: str | None = None, background: str | None = None) -> str:
209
- """
210
- Create or update a memory bank.
211
-
212
- Use this to create new banks for different agents, sessions, or purposes.
213
- Banks are isolated memory stores - each bank has its own memories and personality.
214
-
215
- Args:
216
- bank_id: Unique identifier for the bank (e.g., 'orchestrator-memory', 'agent-1')
217
- name: Human-readable name for the bank
218
- background: Context about what this bank stores or its purpose
219
- """
220
- try:
221
- # Get or create the bank profile (auto-creates with defaults)
222
- await memory.get_bank_profile(bank_id, request_context=RequestContext())
223
-
224
- # Update name and/or background if provided
225
- if name is not None or background is not None:
226
- await memory.update_bank(bank_id, name=name, background=background, request_context=RequestContext())
227
-
228
- # Get final profile and return using BankProfileResponse model
229
- profile = await memory.get_bank_profile(bank_id, request_context=RequestContext())
230
- disposition = profile.get("disposition")
231
- if hasattr(disposition, "model_dump"):
232
- disposition_traits = DispositionTraits(**disposition.model_dump())
233
- else:
234
- disposition_traits = DispositionTraits(
235
- **dict(disposition or {"skepticism": 3, "literalism": 3, "empathy": 3})
236
- )
237
-
238
- response = BankProfileResponse(
239
- bank_id=bank_id,
240
- name=profile.get("name") or "",
241
- disposition=disposition_traits,
242
- background=profile.get("background") or "",
243
- )
244
- return response.model_dump_json(indent=2)
245
- except Exception as e:
246
- logger.error(f"Error creating bank: {e}", exc_info=True)
247
- return json.dumps({"error": str(e)})
54
+ # Configure and register tools using shared module
55
+ config = MCPToolsConfig(
56
+ bank_id_resolver=get_current_bank_id,
57
+ include_bank_id_param=True, # HTTP MCP supports multi-bank via parameter
58
+ tools=None, # All tools
59
+ retain_fire_and_forget=False, # HTTP MCP supports sync/async modes
60
+ )
61
+
62
+ register_mcp_tools(mcp, memory, config)
248
63
 
249
64
  return mcp
250
65