hindsight-api 0.1.5__py3-none-any.whl → 0.1.6__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 (63) hide show
  1. hindsight_api/__init__.py +10 -9
  2. hindsight_api/alembic/env.py +5 -8
  3. hindsight_api/alembic/versions/5a366d414dce_initial_schema.py +266 -180
  4. hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py +32 -32
  5. hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py +11 -11
  6. hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py +7 -12
  7. hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py +23 -15
  8. hindsight_api/alembic/versions/rename_personality_to_disposition.py +30 -21
  9. hindsight_api/api/__init__.py +10 -10
  10. hindsight_api/api/http.py +575 -593
  11. hindsight_api/api/mcp.py +30 -28
  12. hindsight_api/banner.py +13 -6
  13. hindsight_api/config.py +9 -13
  14. hindsight_api/engine/__init__.py +9 -9
  15. hindsight_api/engine/cross_encoder.py +22 -21
  16. hindsight_api/engine/db_utils.py +5 -4
  17. hindsight_api/engine/embeddings.py +22 -21
  18. hindsight_api/engine/entity_resolver.py +81 -75
  19. hindsight_api/engine/llm_wrapper.py +61 -79
  20. hindsight_api/engine/memory_engine.py +603 -625
  21. hindsight_api/engine/query_analyzer.py +100 -97
  22. hindsight_api/engine/response_models.py +105 -106
  23. hindsight_api/engine/retain/__init__.py +9 -16
  24. hindsight_api/engine/retain/bank_utils.py +34 -58
  25. hindsight_api/engine/retain/chunk_storage.py +4 -12
  26. hindsight_api/engine/retain/deduplication.py +9 -28
  27. hindsight_api/engine/retain/embedding_processing.py +4 -11
  28. hindsight_api/engine/retain/embedding_utils.py +3 -4
  29. hindsight_api/engine/retain/entity_processing.py +7 -17
  30. hindsight_api/engine/retain/fact_extraction.py +155 -165
  31. hindsight_api/engine/retain/fact_storage.py +11 -23
  32. hindsight_api/engine/retain/link_creation.py +11 -39
  33. hindsight_api/engine/retain/link_utils.py +166 -95
  34. hindsight_api/engine/retain/observation_regeneration.py +39 -52
  35. hindsight_api/engine/retain/orchestrator.py +72 -62
  36. hindsight_api/engine/retain/types.py +49 -43
  37. hindsight_api/engine/search/__init__.py +5 -5
  38. hindsight_api/engine/search/fusion.py +6 -15
  39. hindsight_api/engine/search/graph_retrieval.py +22 -23
  40. hindsight_api/engine/search/mpfp_retrieval.py +76 -92
  41. hindsight_api/engine/search/observation_utils.py +9 -16
  42. hindsight_api/engine/search/reranking.py +4 -7
  43. hindsight_api/engine/search/retrieval.py +87 -66
  44. hindsight_api/engine/search/scoring.py +5 -7
  45. hindsight_api/engine/search/temporal_extraction.py +8 -11
  46. hindsight_api/engine/search/think_utils.py +115 -39
  47. hindsight_api/engine/search/trace.py +68 -39
  48. hindsight_api/engine/search/tracer.py +44 -35
  49. hindsight_api/engine/search/types.py +20 -17
  50. hindsight_api/engine/task_backend.py +21 -26
  51. hindsight_api/engine/utils.py +25 -10
  52. hindsight_api/main.py +21 -40
  53. hindsight_api/mcp_local.py +190 -0
  54. hindsight_api/metrics.py +44 -30
  55. hindsight_api/migrations.py +10 -8
  56. hindsight_api/models.py +60 -72
  57. hindsight_api/pg0.py +22 -23
  58. hindsight_api/server.py +3 -6
  59. {hindsight_api-0.1.5.dist-info → hindsight_api-0.1.6.dist-info}/METADATA +2 -2
  60. hindsight_api-0.1.6.dist-info/RECORD +64 -0
  61. {hindsight_api-0.1.5.dist-info → hindsight_api-0.1.6.dist-info}/entry_points.txt +1 -0
  62. hindsight_api-0.1.5.dist-info/RECORD +0 -63
  63. {hindsight_api-0.1.5.dist-info → hindsight_api-0.1.6.dist-info}/WHEEL +0 -0
hindsight_api/models.py CHANGED
@@ -1,49 +1,47 @@
1
1
  """
2
2
  SQLAlchemy models for the memory system.
3
3
  """
4
+
4
5
  from datetime import datetime
5
- from typing import Optional
6
- from uuid import UUID as PyUUID, uuid4
6
+ from uuid import UUID as PyUUID
7
7
 
8
+ from pgvector.sqlalchemy import Vector
8
9
  from sqlalchemy import (
9
10
  CheckConstraint,
10
- Column,
11
11
  Float,
12
12
  ForeignKey,
13
13
  ForeignKeyConstraint,
14
14
  Index,
15
15
  Integer,
16
- PrimaryKeyConstraint,
17
16
  Text,
18
17
  func,
18
+ )
19
+ from sqlalchemy import (
19
20
  text as sql_text,
20
21
  )
21
22
  from sqlalchemy.dialects.postgresql import JSONB, TIMESTAMP, UUID
22
23
  from sqlalchemy.ext.asyncio import AsyncAttrs
23
24
  from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
24
- from pgvector.sqlalchemy import Vector
25
25
 
26
26
 
27
27
  class Base(AsyncAttrs, DeclarativeBase):
28
28
  """Base class for all models."""
29
+
29
30
  pass
30
31
 
31
32
 
32
33
  class Document(Base):
33
34
  """Source documents for memory units."""
35
+
34
36
  __tablename__ = "documents"
35
37
 
36
38
  id: Mapped[str] = mapped_column(Text, primary_key=True)
37
39
  bank_id: Mapped[str] = mapped_column(Text, primary_key=True)
38
- original_text: Mapped[Optional[str]] = mapped_column(Text)
39
- content_hash: Mapped[Optional[str]] = mapped_column(Text)
40
+ original_text: Mapped[str | None] = mapped_column(Text)
41
+ content_hash: Mapped[str | None] = mapped_column(Text)
40
42
  doc_metadata: Mapped[dict] = mapped_column("metadata", JSONB, server_default=sql_text("'{}'::jsonb"))
41
- created_at: Mapped[datetime] = mapped_column(
42
- TIMESTAMP(timezone=True), server_default=func.now()
43
- )
44
- updated_at: Mapped[datetime] = mapped_column(
45
- TIMESTAMP(timezone=True), server_default=func.now()
46
- )
43
+ created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
44
+ updated_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
47
45
 
48
46
  # Relationships
49
47
  memory_units = relationship("MemoryUnit", back_populates="document", cascade="all, delete-orphan")
@@ -56,45 +54,42 @@ class Document(Base):
56
54
 
57
55
  class MemoryUnit(Base):
58
56
  """Individual sentence-level memories."""
57
+
59
58
  __tablename__ = "memory_units"
60
59
 
61
60
  id: Mapped[PyUUID] = mapped_column(
62
61
  UUID(as_uuid=True), primary_key=True, server_default=sql_text("gen_random_uuid()")
63
62
  )
64
63
  bank_id: Mapped[str] = mapped_column(Text, nullable=False)
65
- document_id: Mapped[Optional[str]] = mapped_column(Text)
64
+ document_id: Mapped[str | None] = mapped_column(Text)
66
65
  text: Mapped[str] = mapped_column(Text, nullable=False)
67
66
  embedding = mapped_column(Vector(384)) # pgvector type
68
- context: Mapped[Optional[str]] = mapped_column(Text)
69
- event_date: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), nullable=False) # Kept for backward compatibility
70
- occurred_start: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP(timezone=True)) # When fact occurred (range start)
71
- occurred_end: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP(timezone=True)) # When fact occurred (range end)
72
- mentioned_at: Mapped[Optional[datetime]] = mapped_column(TIMESTAMP(timezone=True)) # When fact was mentioned
67
+ context: Mapped[str | None] = mapped_column(Text)
68
+ event_date: Mapped[datetime] = mapped_column(
69
+ TIMESTAMP(timezone=True), nullable=False
70
+ ) # Kept for backward compatibility
71
+ occurred_start: Mapped[datetime | None] = mapped_column(
72
+ TIMESTAMP(timezone=True)
73
+ ) # When fact occurred (range start)
74
+ occurred_end: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True)) # When fact occurred (range end)
75
+ mentioned_at: Mapped[datetime | None] = mapped_column(TIMESTAMP(timezone=True)) # When fact was mentioned
73
76
  fact_type: Mapped[str] = mapped_column(Text, nullable=False, server_default="world")
74
- confidence_score: Mapped[Optional[float]] = mapped_column(Float)
77
+ confidence_score: Mapped[float | None] = mapped_column(Float)
75
78
  access_count: Mapped[int] = mapped_column(Integer, server_default="0")
76
- unit_metadata: Mapped[dict] = mapped_column("metadata", JSONB, server_default=sql_text("'{}'::jsonb")) # User-defined metadata (str->str)
77
- created_at: Mapped[datetime] = mapped_column(
78
- TIMESTAMP(timezone=True), server_default=func.now()
79
- )
80
- updated_at: Mapped[datetime] = mapped_column(
81
- TIMESTAMP(timezone=True), server_default=func.now()
82
- )
79
+ unit_metadata: Mapped[dict] = mapped_column(
80
+ "metadata", JSONB, server_default=sql_text("'{}'::jsonb")
81
+ ) # User-defined metadata (str->str)
82
+ created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
83
+ updated_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
83
84
 
84
85
  # Relationships
85
86
  document = relationship("Document", back_populates="memory_units")
86
87
  unit_entities = relationship("UnitEntity", back_populates="memory_unit", cascade="all, delete-orphan")
87
88
  outgoing_links = relationship(
88
- "MemoryLink",
89
- foreign_keys="MemoryLink.from_unit_id",
90
- back_populates="from_unit",
91
- cascade="all, delete-orphan"
89
+ "MemoryLink", foreign_keys="MemoryLink.from_unit_id", back_populates="from_unit", cascade="all, delete-orphan"
92
90
  )
93
91
  incoming_links = relationship(
94
- "MemoryLink",
95
- foreign_keys="MemoryLink.to_unit_id",
96
- back_populates="to_unit",
97
- cascade="all, delete-orphan"
92
+ "MemoryLink", foreign_keys="MemoryLink.to_unit_id", back_populates="to_unit", cascade="all, delete-orphan"
98
93
  )
99
94
 
100
95
  __table_args__ = (
@@ -110,7 +105,7 @@ class MemoryUnit(Base):
110
105
  "(fact_type = 'opinion' AND confidence_score IS NOT NULL) OR "
111
106
  "(fact_type = 'observation') OR "
112
107
  "(fact_type NOT IN ('opinion', 'observation') AND confidence_score IS NULL)",
113
- name="confidence_score_fact_type_check"
108
+ name="confidence_score_fact_type_check",
114
109
  ),
115
110
  Index("idx_memory_units_bank_id", "bank_id"),
116
111
  Index("idx_memory_units_document_id", "document_id"),
@@ -119,39 +114,46 @@ class MemoryUnit(Base):
119
114
  Index("idx_memory_units_access_count", "access_count", postgresql_ops={"access_count": "DESC"}),
120
115
  Index("idx_memory_units_fact_type", "fact_type"),
121
116
  Index("idx_memory_units_bank_fact_type", "bank_id", "fact_type"),
122
- Index("idx_memory_units_bank_type_date", "bank_id", "fact_type", "event_date", postgresql_ops={"event_date": "DESC"}),
117
+ Index(
118
+ "idx_memory_units_bank_type_date",
119
+ "bank_id",
120
+ "fact_type",
121
+ "event_date",
122
+ postgresql_ops={"event_date": "DESC"},
123
+ ),
123
124
  Index(
124
125
  "idx_memory_units_opinion_confidence",
125
126
  "bank_id",
126
127
  "confidence_score",
127
128
  postgresql_where=sql_text("fact_type = 'opinion'"),
128
- postgresql_ops={"confidence_score": "DESC"}
129
+ postgresql_ops={"confidence_score": "DESC"},
129
130
  ),
130
131
  Index(
131
132
  "idx_memory_units_opinion_date",
132
133
  "bank_id",
133
134
  "event_date",
134
135
  postgresql_where=sql_text("fact_type = 'opinion'"),
135
- postgresql_ops={"event_date": "DESC"}
136
+ postgresql_ops={"event_date": "DESC"},
136
137
  ),
137
138
  Index(
138
139
  "idx_memory_units_observation_date",
139
140
  "bank_id",
140
141
  "event_date",
141
142
  postgresql_where=sql_text("fact_type = 'observation'"),
142
- postgresql_ops={"event_date": "DESC"}
143
+ postgresql_ops={"event_date": "DESC"},
143
144
  ),
144
145
  Index(
145
146
  "idx_memory_units_embedding",
146
147
  "embedding",
147
148
  postgresql_using="hnsw",
148
- postgresql_ops={"embedding": "vector_cosine_ops"}
149
+ postgresql_ops={"embedding": "vector_cosine_ops"},
149
150
  ),
150
151
  )
151
152
 
152
153
 
153
154
  class Entity(Base):
154
155
  """Resolved entities (people, organizations, locations, etc.)."""
156
+
155
157
  __tablename__ = "entities"
156
158
 
157
159
  id: Mapped[PyUUID] = mapped_column(
@@ -160,12 +162,8 @@ class Entity(Base):
160
162
  canonical_name: Mapped[str] = mapped_column(Text, nullable=False)
161
163
  bank_id: Mapped[str] = mapped_column(Text, nullable=False)
162
164
  entity_metadata: Mapped[dict] = mapped_column("metadata", JSONB, server_default=sql_text("'{}'::jsonb"))
163
- first_seen: Mapped[datetime] = mapped_column(
164
- TIMESTAMP(timezone=True), server_default=func.now()
165
- )
166
- last_seen: Mapped[datetime] = mapped_column(
167
- TIMESTAMP(timezone=True), server_default=func.now()
168
- )
165
+ first_seen: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
166
+ last_seen: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
169
167
  mention_count: Mapped[int] = mapped_column(Integer, server_default="1")
170
168
 
171
169
  # Relationships
@@ -175,13 +173,13 @@ class Entity(Base):
175
173
  "EntityCooccurrence",
176
174
  foreign_keys="EntityCooccurrence.entity_id_1",
177
175
  back_populates="entity_1",
178
- cascade="all, delete-orphan"
176
+ cascade="all, delete-orphan",
179
177
  )
180
178
  cooccurrences_2 = relationship(
181
179
  "EntityCooccurrence",
182
180
  foreign_keys="EntityCooccurrence.entity_id_2",
183
181
  back_populates="entity_2",
184
- cascade="all, delete-orphan"
182
+ cascade="all, delete-orphan",
185
183
  )
186
184
 
187
185
  __table_args__ = (
@@ -193,6 +191,7 @@ class Entity(Base):
193
191
 
194
192
  class UnitEntity(Base):
195
193
  """Association between memory units and entities."""
194
+
196
195
  __tablename__ = "unit_entities"
197
196
 
198
197
  unit_id: Mapped[PyUUID] = mapped_column(
@@ -214,6 +213,7 @@ class UnitEntity(Base):
214
213
 
215
214
  class EntityCooccurrence(Base):
216
215
  """Materialized cache of entity co-occurrences."""
216
+
217
217
  __tablename__ = "entity_cooccurrences"
218
218
 
219
219
  entity_id_1: Mapped[PyUUID] = mapped_column(
@@ -223,9 +223,7 @@ class EntityCooccurrence(Base):
223
223
  UUID(as_uuid=True), ForeignKey("entities.id", ondelete="CASCADE"), primary_key=True
224
224
  )
225
225
  cooccurrence_count: Mapped[int] = mapped_column(Integer, server_default="1")
226
- last_cooccurred: Mapped[datetime] = mapped_column(
227
- TIMESTAMP(timezone=True), server_default=func.now()
228
- )
226
+ last_cooccurred: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
229
227
 
230
228
  # Relationships
231
229
  entity_1 = relationship("Entity", foreign_keys=[entity_id_1], back_populates="cooccurrences_1")
@@ -241,6 +239,7 @@ class EntityCooccurrence(Base):
241
239
 
242
240
  class MemoryLink(Base):
243
241
  """Links between memory units (temporal, semantic, entity)."""
242
+
244
243
  __tablename__ = "memory_links"
245
244
 
246
245
  from_unit_id: Mapped[PyUUID] = mapped_column(
@@ -250,13 +249,11 @@ class MemoryLink(Base):
250
249
  UUID(as_uuid=True), ForeignKey("memory_units.id", ondelete="CASCADE"), primary_key=True
251
250
  )
252
251
  link_type: Mapped[str] = mapped_column(Text, primary_key=True)
253
- entity_id: Mapped[Optional[PyUUID]] = mapped_column(
252
+ entity_id: Mapped[PyUUID | None] = mapped_column(
254
253
  UUID(as_uuid=True), ForeignKey("entities.id", ondelete="CASCADE"), primary_key=True
255
254
  )
256
255
  weight: Mapped[float] = mapped_column(Float, nullable=False, server_default="1.0")
257
- created_at: Mapped[datetime] = mapped_column(
258
- TIMESTAMP(timezone=True), server_default=func.now()
259
- )
256
+ created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
260
257
 
261
258
  # Relationships
262
259
  from_unit = relationship("MemoryUnit", foreign_keys=[from_unit_id], back_populates="outgoing_links")
@@ -266,7 +263,7 @@ class MemoryLink(Base):
266
263
  __table_args__ = (
267
264
  CheckConstraint(
268
265
  "link_type IN ('temporal', 'semantic', 'entity', 'causes', 'caused_by', 'enables', 'prevents')",
269
- name="memory_links_link_type_check"
266
+ name="memory_links_link_type_check",
270
267
  ),
271
268
  CheckConstraint("weight >= 0.0 AND weight <= 1.0", name="memory_links_weight_check"),
272
269
  Index("idx_memory_links_from", "from_unit_id"),
@@ -278,31 +275,22 @@ class MemoryLink(Base):
278
275
  "from_unit_id",
279
276
  "weight",
280
277
  postgresql_where=sql_text("weight >= 0.1"),
281
- postgresql_ops={"weight": "DESC"}
278
+ postgresql_ops={"weight": "DESC"},
282
279
  ),
283
280
  )
284
281
 
285
282
 
286
283
  class Bank(Base):
287
284
  """Memory bank profiles with disposition traits and background."""
285
+
288
286
  __tablename__ = "banks"
289
287
 
290
288
  bank_id: Mapped[str] = mapped_column(Text, primary_key=True)
291
289
  disposition: Mapped[dict] = mapped_column(
292
- JSONB,
293
- nullable=False,
294
- server_default=sql_text(
295
- '\'{"skepticism": 3, "literalism": 3, "empathy": 3}\'::jsonb'
296
- )
290
+ JSONB, nullable=False, server_default=sql_text('\'{"skepticism": 3, "literalism": 3, "empathy": 3}\'::jsonb')
297
291
  )
298
292
  background: Mapped[str] = mapped_column(Text, nullable=False, server_default="")
299
- created_at: Mapped[datetime] = mapped_column(
300
- TIMESTAMP(timezone=True), server_default=func.now()
301
- )
302
- updated_at: Mapped[datetime] = mapped_column(
303
- TIMESTAMP(timezone=True), server_default=func.now()
304
- )
293
+ created_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
294
+ updated_at: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), server_default=func.now())
305
295
 
306
- __table_args__ = (
307
- Index("idx_banks_bank_id", "bank_id"),
308
- )
296
+ __table_args__ = (Index("idx_banks_bank_id", "bank_id"),)
hindsight_api/pg0.py CHANGED
@@ -1,12 +1,10 @@
1
1
  import asyncio
2
2
  import logging
3
- from typing import Optional
4
3
 
5
4
  from pg0 import Pg0
6
5
 
7
6
  logger = logging.getLogger(__name__)
8
7
 
9
- DEFAULT_PORT = 5555
10
8
  DEFAULT_USERNAME = "hindsight"
11
9
  DEFAULT_PASSWORD = "hindsight"
12
10
  DEFAULT_DATABASE = "hindsight"
@@ -17,34 +15,38 @@ class EmbeddedPostgres:
17
15
 
18
16
  def __init__(
19
17
  self,
20
- port: int = DEFAULT_PORT,
18
+ port: int | None = None,
21
19
  username: str = DEFAULT_USERNAME,
22
20
  password: str = DEFAULT_PASSWORD,
23
21
  database: str = DEFAULT_DATABASE,
24
22
  name: str = "hindsight",
25
23
  **kwargs,
26
24
  ):
27
- self.port = port
25
+ self.port = port # None means pg0 will auto-assign
28
26
  self.username = username
29
27
  self.password = password
30
28
  self.database = database
31
29
  self.name = name
32
- self._pg0: Optional[Pg0] = None
30
+ self._pg0: Pg0 | None = None
33
31
 
34
32
  def _get_pg0(self) -> Pg0:
35
33
  if self._pg0 is None:
36
- self._pg0 = Pg0(
37
- name=self.name,
38
- port=self.port,
39
- username=self.username,
40
- password=self.password,
41
- database=self.database,
42
- )
34
+ kwargs = {
35
+ "name": self.name,
36
+ "username": self.username,
37
+ "password": self.password,
38
+ "database": self.database,
39
+ }
40
+ # Only set port if explicitly specified
41
+ if self.port is not None:
42
+ kwargs["port"] = self.port
43
+ self._pg0 = Pg0(**kwargs)
43
44
  return self._pg0
44
45
 
45
- async def start(self, max_retries: int = 3, retry_delay: float = 2.0) -> str:
46
+ async def start(self, max_retries: int = 5, retry_delay: float = 4.0) -> str:
46
47
  """Start the PostgreSQL server with retry logic."""
47
- logger.info(f"Starting embedded PostgreSQL (name: {self.name}, port: {self.port})...")
48
+ port_info = f"port={self.port}" if self.port else "port=auto"
49
+ logger.info(f"Starting embedded PostgreSQL (name={self.name}, {port_info})...")
48
50
 
49
51
  pg0 = self._get_pg0()
50
52
  last_error = None
@@ -53,9 +55,9 @@ class EmbeddedPostgres:
53
55
  try:
54
56
  loop = asyncio.get_event_loop()
55
57
  info = await loop.run_in_executor(None, pg0.start)
56
- logger.info(f"PostgreSQL started on port {self.port}")
57
- # Construct URI manually since pg0-embedded may return None
58
- uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
58
+ # Get URI from pg0 (includes auto-assigned port)
59
+ uri = info.uri
60
+ logger.info(f"PostgreSQL started: {uri}")
59
61
  return uri
60
62
  except Exception as e:
61
63
  last_error = str(e)
@@ -68,8 +70,7 @@ class EmbeddedPostgres:
68
70
  logger.debug(f"pg0 start attempt {attempt}/{max_retries} failed: {last_error}")
69
71
 
70
72
  raise RuntimeError(
71
- f"Failed to start embedded PostgreSQL after {max_retries} attempts. "
72
- f"Last error: {last_error}"
73
+ f"Failed to start embedded PostgreSQL after {max_retries} attempts. Last error: {last_error}"
73
74
  )
74
75
 
75
76
  async def stop(self) -> None:
@@ -91,9 +92,7 @@ class EmbeddedPostgres:
91
92
  pg0 = self._get_pg0()
92
93
  loop = asyncio.get_event_loop()
93
94
  info = await loop.run_in_executor(None, pg0.info)
94
- # Construct URI manually since pg0-embedded may return None
95
- uri = info.uri if info and info.uri else f"postgresql://{self.username}:{self.password}@localhost:{self.port}/{self.database}"
96
- return uri
95
+ return info.uri
97
96
 
98
97
  async def is_running(self) -> bool:
99
98
  """Check if the PostgreSQL server is currently running."""
@@ -112,7 +111,7 @@ class EmbeddedPostgres:
112
111
  return await self.start()
113
112
 
114
113
 
115
- _default_instance: Optional[EmbeddedPostgres] = None
114
+ _default_instance: EmbeddedPostgres | None = None
116
115
 
117
116
 
118
117
  def get_embedded_postgres() -> EmbeddedPostgres:
hindsight_api/server.py CHANGED
@@ -6,6 +6,7 @@ This module provides the ASGI app for uvicorn import string usage:
6
6
 
7
7
  For CLI usage, use the hindsight-api command instead.
8
8
  """
9
+
9
10
  import os
10
11
  import warnings
11
12
 
@@ -29,15 +30,11 @@ config.configure_logging()
29
30
  _memory = MemoryEngine()
30
31
 
31
32
  # Create unified app with both HTTP and optionally MCP
32
- app = create_app(
33
- memory=_memory,
34
- http_api_enabled=True,
35
- mcp_api_enabled=config.mcp_enabled,
36
- mcp_mount_path="/mcp"
37
- )
33
+ app = create_app(memory=_memory, http_api_enabled=True, mcp_api_enabled=config.mcp_enabled, mcp_mount_path="/mcp")
38
34
 
39
35
 
40
36
  if __name__ == "__main__":
41
37
  # When run directly, delegate to the CLI
42
38
  from hindsight_api.main import main
39
+
43
40
  main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hindsight-api
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: Temporal + Semantic + Entity Memory System for AI agents using PostgreSQL
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: alembic>=1.17.1
@@ -17,7 +17,7 @@ Requires-Dist: opentelemetry-api>=1.20.0
17
17
  Requires-Dist: opentelemetry-exporter-prometheus>=0.41b0
18
18
  Requires-Dist: opentelemetry-instrumentation-fastapi>=0.41b0
19
19
  Requires-Dist: opentelemetry-sdk>=1.20.0
20
- Requires-Dist: pg0-embedded>=0.1.0
20
+ Requires-Dist: pg0-embedded>=0.11.0
21
21
  Requires-Dist: pgvector>=0.4.1
22
22
  Requires-Dist: psycopg2-binary>=2.9.11
23
23
  Requires-Dist: pydantic>=2.0.0
@@ -0,0 +1,64 @@
1
+ hindsight_api/__init__.py,sha256=paLZxYov7BBgbOSl1RTNtFYvqHXlZTzTEDygR3kAFLc,1140
2
+ hindsight_api/banner.py,sha256=BXn-jhkXe4xi-YV4JeuaVvjYhTMs96O43XoOMv4Cd28,4591
3
+ hindsight_api/config.py,sha256=qxdxmeQWJozKIjMUe-Aza9hGIgT34HxMnXs0gh3uXXs,5538
4
+ hindsight_api/main.py,sha256=TO5zLzXpu-CjGfvLHdZFEHerrJbNns2cQGlc4gofaPI,5970
5
+ hindsight_api/mcp_local.py,sha256=ozKMv-PrehzZTLawscP-TDePwqiOH962HCQzTa9x8AY,6646
6
+ hindsight_api/metrics.py,sha256=sQI5MhC2xj9ONZ6Hdjf6r6r3NbYYd3ExyVOn1Uky49A,7239
7
+ hindsight_api/migrations.py,sha256=bN9ejR3cn7EAP3LFkpAjnWsUm9kykgzbzqeCB9HMPvA,7315
8
+ hindsight_api/models.py,sha256=vLFkxykmK8KOoN_sQz4SsiJS6vqOjFIv_82BuKg8qD8,12329
9
+ hindsight_api/pg0.py,sha256=y8EE3v1q2OUJbsSHl-hG_sPZEIWQrgkxrGcf-kuEECE,4624
10
+ hindsight_api/server.py,sha256=OrSd0G-79U07EXFc838c1vzUL-1O6wuxTMqUmMINpGY,1247
11
+ hindsight_api/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
12
+ hindsight_api/alembic/env.py,sha256=x5MoBxdfRunSve1zARCOZ8KZDg2M3-NYrjJsR1hePg4,4753
13
+ hindsight_api/alembic/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
14
+ hindsight_api/alembic/versions/5a366d414dce_initial_schema.py,sha256=g3G7fV70Z10PZxwTrTmR34OAlEZjQTLJKr-Ol54JqrQ,17665
15
+ hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py,sha256=MaHFU4JczUIFLeUMBTKIV3ocuclil55N9fPPim-HRfk,2599
16
+ hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py,sha256=ChqkHANauZb4-nBt2uepoZN3q0vRzN6aRsWTGueULiA,1146
17
+ hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py,sha256=28KBE6mAAj2PEXm0iALJOiMcjn4eTx_X5nUPaJ1aRYk,1480
18
+ hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py,sha256=LLj0Tl6Kjw5uZPo7lCcG2IH8lFSPEmc9jG_riMF3Bj0,2370
19
+ hindsight_api/alembic/versions/rename_personality_to_disposition.py,sha256=gpMSG8hdvqn9__lGgS0EE2de1nki1YAaCEI3pDdJRzA,2281
20
+ hindsight_api/api/__init__.py,sha256=zoDWA86ttx-UriC35UIgdPswIrau7GuMWTN63wYsUdM,2916
21
+ hindsight_api/api/http.py,sha256=eYVnsQwx5LW3MvdcAQjiLw6WwBobw5aGeYSPYLIFllE,70922
22
+ hindsight_api/api/mcp.py,sha256=I9C_jUz6d7efMstBfOyoqnnsB94JU6c2mMk6eQ_KDz0,7462
23
+ hindsight_api/engine/__init__.py,sha256=z6srTnyvGQM0eya7E8r2yagTAc4C7IhHauUK8NM-gW8,1406
24
+ hindsight_api/engine/cross_encoder.py,sha256=5WmUx9yfJdIwZ0nA218O-mMKQJ7EKaPOtwhMiDbG8KQ,10483
25
+ hindsight_api/engine/db_utils.py,sha256=0T5tL2SZ49JQihfyZYlTDThIfocKzkr1OpxQpJzPCGE,2687
26
+ hindsight_api/engine/embeddings.py,sha256=IEdP5-p6oTJRRKV2JzUEojByJGShUEmkInCyA9wM8tg,10219
27
+ hindsight_api/engine/entity_resolver.py,sha256=XHAViwIaEXMUhp9Eifvx0b3MZ4QwiFvH_k_ZHTwczxE,23151
28
+ hindsight_api/engine/llm_wrapper.py,sha256=-EQnDoMr4BHTcp24dGNiOnYVGA5uGYmGFT5qQHhxGwY,21134
29
+ hindsight_api/engine/memory_engine.py,sha256=l6NeQ_xHj8YfOs6Jpr6k6nYCUFRpZYIYZgf8H6JB7U8,135992
30
+ hindsight_api/engine/query_analyzer.py,sha256=DKFxmyyVVc59zwKbbGx4D22UVp6TxmD7jAa7cg9FGSU,19641
31
+ hindsight_api/engine/response_models.py,sha256=QeESHC7oh84SYPDrR6FqHjiGBZnTAzo61IDB-qwVTSY,8737
32
+ hindsight_api/engine/task_backend.py,sha256=XT0C-QFWfdcOHJjplkoarlnwvz-kCF2l6wAGW1dTJkw,7144
33
+ hindsight_api/engine/utils.py,sha256=TwuipFRvN0Pu196JLakzQ71E3GAwySc5q6pByC81Ak4,6991
34
+ hindsight_api/engine/retain/__init__.py,sha256=t6q3-_kf4iYTl9j2PVB6laqMSs6UuPeXBSYMW6HT1sA,1152
35
+ hindsight_api/engine/retain/bank_utils.py,sha256=-Q_GW_F1rmT6Twxgk7aLPmfintLp6TQhC5xT0i5hZzg,13970
36
+ hindsight_api/engine/retain/chunk_storage.py,sha256=yIofSL6RwMOIBR_xo1sTOUdkYQoRZBfjdqYuH-dj1EY,2012
37
+ hindsight_api/engine/retain/deduplication.py,sha256=kqs7I7eIc_ppvgAF9GlzL6fSGuEEzrgw17-7NdyUDis,3099
38
+ hindsight_api/engine/retain/embedding_processing.py,sha256=R35oyKYIKjuqC-yZl5Ru56F8xRe0N6KW_9p5PZ9CBi0,1649
39
+ hindsight_api/engine/retain/embedding_utils.py,sha256=uulXIBiA7XNsj16K1VGawR3s5jV-hsAmvmoCi-IodpU,1565
40
+ hindsight_api/engine/retain/entity_processing.py,sha256=5EYzyH_JjbhYQ0zQ8gX6xs0wCH6vmxMYUe6_qVJdvQA,2547
41
+ hindsight_api/engine/retain/fact_extraction.py,sha256=E9AswSrqx3X74gj5-qstbm2wqPv4kUMddkdn5yExKvI,50166
42
+ hindsight_api/engine/retain/fact_storage.py,sha256=SmWbdNTrOJW6MOHGOQ094f5DJSqasYp6yXGuxjh4_IA,5513
43
+ hindsight_api/engine/retain/link_creation.py,sha256=KP2kGU2VCymJptgw0hjaSdsjvncBgNp3P_A4OB_qx-w,3082
44
+ hindsight_api/engine/retain/link_utils.py,sha256=sB4aI3Ai7ukm1yQ6C_sotZ1inljjtDM8I9kSr8-a12o,32697
45
+ hindsight_api/engine/retain/observation_regeneration.py,sha256=HdKiVakeAEfBBUpKYYn2Rbb9jrx4FBhICEMZJ-sFQWU,7960
46
+ hindsight_api/engine/retain/orchestrator.py,sha256=obOpfzpAAg6PfTxR45RnKPvXnndNfUlmShkImj1cYOA,17418
47
+ hindsight_api/engine/retain/types.py,sha256=sez-Rq5nNNUnu6Z04QrmnR-CbrkXeQ1myAXHj9X79Pw,6379
48
+ hindsight_api/engine/search/__init__.py,sha256=YPz_4g7IOabx078Xwg3RBfbOpJ649NRwNfe0gTI9P1U,802
49
+ hindsight_api/engine/search/fusion.py,sha256=cY81BH9U5RyWrPXbQnrDBghtelDMckZWCke9aqMyNnQ,4220
50
+ hindsight_api/engine/search/graph_retrieval.py,sha256=AiC2oSRuZBdD5MmtIk0xSG7CxI5E6uQZe2-IbPqvJQw,8544
51
+ hindsight_api/engine/search/mpfp_retrieval.py,sha256=_OJUxgOYw169OjIxfOjpowg1gstXvVC0VhmJaClBJz8,13849
52
+ hindsight_api/engine/search/observation_utils.py,sha256=rlvGA4oFomMZNCZiJvPIQ0iwGaq9XqhRM530unqziCE,4243
53
+ hindsight_api/engine/search/reranking.py,sha256=RZSKe3JDkLfEdTAdgbS-xZka6Jq4mmTBPDXBpyH73zA,3278
54
+ hindsight_api/engine/search/retrieval.py,sha256=vs-kX5U5Vq4VV6lKq5Aoq1TzlJTtw5vDfnU4gPJ49Aw,25190
55
+ hindsight_api/engine/search/scoring.py,sha256=7jbBtdnow7JU0d8xdW-ZqYvP4s-TYX2tqPhu2DiqHUI,5132
56
+ hindsight_api/engine/search/temporal_extraction.py,sha256=j7hPqpx2jMdR2BqgFrL-rrV2Hzq8HV24MtjYLJqVl2U,1732
57
+ hindsight_api/engine/search/think_utils.py,sha256=rTRyoefRkZc65gcPQtffKiqHinpi7rrRD3m6i57fxNY,13900
58
+ hindsight_api/engine/search/trace.py,sha256=UTCmNRfAvIvDFGm5ifkuUk6JOKYrLlA_rPA72Zz_DfI,11217
59
+ hindsight_api/engine/search/tracer.py,sha256=6OFlkRy_41gr2kgJZ1cmxnerUO069wPfnmiQrMvkOpg,15459
60
+ hindsight_api/engine/search/types.py,sha256=2cK-5oynPTWc7UxnA7TFnwzNkcujCfOUvVf5VCk_srM,5594
61
+ hindsight_api-0.1.6.dist-info/METADATA,sha256=5vGOGWT1fI8hafqlmoIbTtBA8nARhZGBGvO5dxUqfMU,1524
62
+ hindsight_api-0.1.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
63
+ hindsight_api-0.1.6.dist-info/entry_points.txt,sha256=vqZv5WLHbSx8vyec5RtMlUqtE_ul7DTgEVODSmou6Og,109
64
+ hindsight_api-0.1.6.dist-info/RECORD,,
@@ -1,2 +1,3 @@
1
1
  [console_scripts]
2
2
  hindsight-api = hindsight_api.main:main
3
+ hindsight-local-mcp = hindsight_api.mcp_local:main
@@ -1,63 +0,0 @@
1
- hindsight_api/__init__.py,sha256=gPkRHnMATZqBgc7b-Mcro4f_gY9W0BlnGBE0zg1t_IY,1139
2
- hindsight_api/banner.py,sha256=0dsNMXZSuOlj5lkzFykYB19BBOaePgzDTPydPEFel9M,4604
3
- hindsight_api/config.py,sha256=rZveBJXViU2q7TrcY5KQnVCN3WpqXAtbp8kLMgjgy-U,5502
4
- hindsight_api/main.py,sha256=aPftkauWHDaC7We0OF08EsDYuwjBHMZTPznoan-nxnc,6131
5
- hindsight_api/metrics.py,sha256=j4-eeqVjjcGQxAxS_GgEaBNm10KdUxrGS_I2d1IM1hY,7255
6
- hindsight_api/migrations.py,sha256=nSbU37ZszVZifYJTU_vEXfusTxWaUea9dRi7-Ao3-SQ,7349
7
- hindsight_api/models.py,sha256=ncIi8agl3PVk7ffyXlJosFym1jJZZhVmXTguZ3EnAEc,12515
8
- hindsight_api/pg0.py,sha256=cGAnMif5mFeBV2XCmOPKsDajU6o0L-qud7VOKt0gchk,4786
9
- hindsight_api/server.py,sha256=C_w3_xzKRVkSsFkujhMz9S4nDlAc0eOFClGIefTCZIk,1263
10
- hindsight_api/alembic/README,sha256=MVlc9TYmr57RbhXET6QxgyCcwWP7w-vLkEsirENqiIQ,38
11
- hindsight_api/alembic/env.py,sha256=i0gc3GN2rWidtqRp-vdvnJTIR0zl1X4Uokqp_WnTsAo,4837
12
- hindsight_api/alembic/script.py.mako,sha256=04kgeBtNMa4cCnG8CfQcKt6P6rnloIfj8wy0u_DBydM,704
13
- hindsight_api/alembic/versions/5a366d414dce_initial_schema.py,sha256=qTrvBWf-48sL2kx7eNq1BoDjF_QfePGq2-wKrK__wWk,16774
14
- hindsight_api/alembic/versions/b7c4d8e9f1a2_add_chunks_table.py,sha256=g0edMh_4w8WDVcnB-GA1l-RdreYJkV-kJWZX9VJHYp8,2592
15
- hindsight_api/alembic/versions/c8e5f2a3b4d1_add_retain_params_to_documents.py,sha256=brlAuHO5ygarkfsjW-p70NiVDGfj98BjczaptGPyYNg,1159
16
- hindsight_api/alembic/versions/d9f6a3b4c5e2_rename_bank_to_interactions.py,sha256=pLz_s5kV3IHQ3TrpvHmtXQOkdfK4iQ07w93dEsXu3Qk,1536
17
- hindsight_api/alembic/versions/e0a1b2c3d4e5_disposition_to_3_traits.py,sha256=fykAU4V4jq1wVpCBoH0TzvSFyeyxZtk-6hpaZAbrFxU,2327
18
- hindsight_api/alembic/versions/rename_personality_to_disposition.py,sha256=xlp-Is96e3TvCwSqhPctQRqLBHcl3dvDmlzbCMZGw1A,2196
19
- hindsight_api/api/__init__.py,sha256=dIJqoygqYaEgm-Bd7qwZ4UTnb9UPyXtlDxZnQpvVC0o,2946
20
- hindsight_api/api/http.py,sha256=G23QBZw097boDBNYeox_MdfLWdmDUZczrakTvGTzb3Q,71195
21
- hindsight_api/api/mcp.py,sha256=Ugkb4LtGAvi0IvO2wLvJzK62KUGTOmNpYEt1f3R-674,7584
22
- hindsight_api/engine/__init__.py,sha256=W_y6iAHgu-HUpvdXlI6JJ0KO42wVkrWvcUSJZqTCj_M,1406
23
- hindsight_api/engine/cross_encoder.py,sha256=0LfuhhvL2wmafAxH0VytcmVAV0X5RzrfZKskOEVj8jI,10489
24
- hindsight_api/engine/db_utils.py,sha256=p1Ne70wPP327xdPI_XjMfnagilY8sknbkhEIZuED6DU,2724
25
- hindsight_api/engine/embeddings.py,sha256=RdK9A3lUjp1FZFArllhTgKo70Pot4ZUEJ1Pw70BpNmk,10218
26
- hindsight_api/engine/entity_resolver.py,sha256=w5DPCuYNsK4GF8Qe3oY7jCKcOT1WYx2h0YD1nX0QRtA,23184
27
- hindsight_api/engine/llm_wrapper.py,sha256=SEzgGJRMVCOwt67J5Ggjyayk-7fWiD7OLbwYLDjsdOw,21401
28
- hindsight_api/engine/memory_engine.py,sha256=saE8flEFNIP9I0XQ7HiNBwo2-hK63e5MVGGEVQxV7oU,135905
29
- hindsight_api/engine/query_analyzer.py,sha256=K0QCg7tsbqtwC7TR5wt3FPoP8QDuZsX9r0Zljc8nnYo,19733
30
- hindsight_api/engine/response_models.py,sha256=e-_vE1zAVFLpkl6SeHIYvHcQ4Z-AaOdq0jjjhh8yHk4,8683
31
- hindsight_api/engine/task_backend.py,sha256=ojxMC9PeHdnkWVs2ozeqycjI_1mmpkDa0_Qfej9AHrg,7287
32
- hindsight_api/engine/utils.py,sha256=VAjpZSbdiwhlE6cDlYfTt_-5hIJ--0xtfixETK0LPSk,6910
33
- hindsight_api/engine/retain/__init__.py,sha256=L_QuR1YLHsJ7OCmVFNsZe8WDjbsTTHL-wCiUXtw1aUE,1230
34
- hindsight_api/engine/retain/bank_utils.py,sha256=r-_411UuuQwxlIxEteA2GE_Wr9BdsNt0OVCjaJgcISU,14143
35
- hindsight_api/engine/retain/chunk_storage.py,sha256=rjmfnllS185tmjJGkMjWZ9q_6hJO4N6Ll9jgPx6f5xo,2081
36
- hindsight_api/engine/retain/deduplication.py,sha256=9YXgVI_m1Mtz5Cv46ZceCEs0GwpLqTPHrZ-vlWlXk6I,3313
37
- hindsight_api/engine/retain/embedding_processing.py,sha256=cHTt3rPvDCWBWVPfSeg6bwH8HoXYGmP4bvS21boNONI,1734
38
- hindsight_api/engine/retain/embedding_utils.py,sha256=Q24h_iw6pRAW2vDWPvauWY1o3bXLzW3eWvSxDALDiE0,1588
39
- hindsight_api/engine/retain/entity_processing.py,sha256=F_6yYjf7Me5khg-X57ZW4wK5BBAmzMpry-TXwVFQZ-8,2658
40
- hindsight_api/engine/retain/fact_extraction.py,sha256=dZ0FYepvndUfWTowGxM5vrrF0NV_LIIGsANA6Ze6Mf4,50818
41
- hindsight_api/engine/retain/fact_storage.py,sha256=rKJiWr_1lrqyB6s0mTCnTiHVZIUbCfd3zigNwISnVPI,5637
42
- hindsight_api/engine/retain/link_creation.py,sha256=rkYKO73dWBL8BbRBeiwNgHzwrU-sKWUjmrgLIxr3LiA,3280
43
- hindsight_api/engine/retain/link_utils.py,sha256=kTMxO9fOXHQvRJZ-gsTrdrKmfw16trWKtvkC2ahQ8o0,31640
44
- hindsight_api/engine/retain/observation_regeneration.py,sha256=ykEMZihF1Vt8Z7427k1OJKyEjYp0qIs9P1IqP6eyI58,8069
45
- hindsight_api/engine/retain/orchestrator.py,sha256=z71wMuJsdjLFlhhwnLHuJ3Y3QQk-9w_faKn1zZUYCXw,17156
46
- hindsight_api/engine/retain/types.py,sha256=JJ4t8Qtp64kTPB9CKOFDXqdos2i8GZXmJZNzBDaNwHY,6514
47
- hindsight_api/engine/search/__init__.py,sha256=Ug0TLmgHRR1Dv2gkxXsYwAe4TxuYnjYjXPufuijcMsI,802
48
- hindsight_api/engine/search/fusion.py,sha256=so6LU7kWRR-VJd1Pxlu8idRJ7P2WLCoDwXUnb8jQifo,4309
49
- hindsight_api/engine/search/graph_retrieval.py,sha256=hHscHqTIrX4eCUuZXX3R7hqH0cUHgKXMVexYljvD3B0,8592
50
- hindsight_api/engine/search/mpfp_retrieval.py,sha256=L-Aorab-kNocYjymGLwBaAEQusGYCJMwXIEJQIplrBk,14154
51
- hindsight_api/engine/search/observation_utils.py,sha256=SPrDx6M0daJ_zLLkk78GlQIG3EL7DqMKSu_etKerUfU,4331
52
- hindsight_api/engine/search/reranking.py,sha256=znjN78VfuT4PqprhGRPd2B9WtVMhAU5A662s0xCvU7g,3329
53
- hindsight_api/engine/search/retrieval.py,sha256=ekugBzcANz5q6SyIIX00HQza0phVUNU0xL4xqbXwvwk,24998
54
- hindsight_api/engine/search/scoring.py,sha256=feFPalpbIMndp8j2Ab0zvu7fRq3c43Wmzrjw3piQ0eM,5167
55
- hindsight_api/engine/search/temporal_extraction.py,sha256=5klrZdza3mkgk5A15_m_j4IIfOHMc6fUR9UJuzLa790,1812
56
- hindsight_api/engine/search/think_utils.py,sha256=VJJXFmBg03yO4Mg--UBMlTQW9IZOj2eyTZztjzhT8F8,11315
57
- hindsight_api/engine/search/trace.py,sha256=YYaOQ_OPgxzDdrGlNwxd4Pp6BcDyuCM4wegAp4esZ6U,11170
58
- hindsight_api/engine/search/tracer.py,sha256=qsMGZ63412dghSbvO8gKYyAT3MzXU_wTY9cJorgIa7E,15399
59
- hindsight_api/engine/search/types.py,sha256=fAG2BocKLGBQ6dEbT3UzZA1JZaiJlco_BJ5Dz45MKQA,5652
60
- hindsight_api-0.1.5.dist-info/METADATA,sha256=dhaSenCcXJEspSk8-wVOhpnln6XtJ9aoqv0B_Um818o,1523
61
- hindsight_api-0.1.5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
62
- hindsight_api-0.1.5.dist-info/entry_points.txt,sha256=ZDj1gJCi6Ga6VLdPgRSrRizQ4dUTreefjeG_tO1CuHk,58
63
- hindsight_api-0.1.5.dist-info/RECORD,,