hindsight-client 0.3.0__py3-none-any.whl → 0.4.1__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 (89) hide show
  1. hindsight_client/__init__.py +9 -8
  2. hindsight_client/hindsight_client.py +394 -59
  3. {hindsight_client-0.3.0.dist-info → hindsight_client-0.4.1.dist-info}/METADATA +1 -1
  4. hindsight_client-0.4.1.dist-info/RECORD +89 -0
  5. hindsight_client_api/__init__.py +26 -2
  6. hindsight_client_api/api/__init__.py +2 -0
  7. hindsight_client_api/api/banks_api.py +998 -132
  8. hindsight_client_api/api/directives_api.py +1619 -0
  9. hindsight_client_api/api/documents_api.py +1 -1
  10. hindsight_client_api/api/entities_api.py +10 -7
  11. hindsight_client_api/api/memory_api.py +1 -1
  12. hindsight_client_api/api/mental_models_api.py +1897 -0
  13. hindsight_client_api/api/monitoring_api.py +247 -1
  14. hindsight_client_api/api/operations_api.py +351 -5
  15. hindsight_client_api/api_client.py +1 -1
  16. hindsight_client_api/configuration.py +2 -2
  17. hindsight_client_api/exceptions.py +1 -1
  18. hindsight_client_api/models/__init__.py +23 -1
  19. hindsight_client_api/models/add_background_request.py +3 -3
  20. hindsight_client_api/models/async_operation_submit_response.py +89 -0
  21. hindsight_client_api/models/background_response.py +11 -4
  22. hindsight_client_api/models/bank_list_item.py +7 -7
  23. hindsight_client_api/models/bank_list_response.py +1 -1
  24. hindsight_client_api/models/bank_profile_response.py +12 -5
  25. hindsight_client_api/models/bank_stats_response.py +16 -5
  26. hindsight_client_api/models/budget.py +1 -1
  27. hindsight_client_api/models/cancel_operation_response.py +1 -1
  28. hindsight_client_api/models/chunk_data.py +1 -1
  29. hindsight_client_api/models/chunk_include_options.py +1 -1
  30. hindsight_client_api/models/chunk_response.py +1 -1
  31. hindsight_client_api/models/consolidation_response.py +89 -0
  32. hindsight_client_api/models/create_bank_request.py +9 -2
  33. hindsight_client_api/models/create_directive_request.py +95 -0
  34. hindsight_client_api/models/create_mental_model_request.py +100 -0
  35. hindsight_client_api/models/create_mental_model_response.py +87 -0
  36. hindsight_client_api/models/delete_document_response.py +1 -1
  37. hindsight_client_api/models/delete_response.py +1 -1
  38. hindsight_client_api/models/directive_list_response.py +95 -0
  39. hindsight_client_api/models/directive_response.py +113 -0
  40. hindsight_client_api/models/disposition_traits.py +1 -1
  41. hindsight_client_api/models/document_response.py +1 -1
  42. hindsight_client_api/models/entity_detail_response.py +1 -1
  43. hindsight_client_api/models/entity_include_options.py +1 -1
  44. hindsight_client_api/models/entity_input.py +1 -1
  45. hindsight_client_api/models/entity_list_item.py +1 -1
  46. hindsight_client_api/models/entity_list_response.py +1 -1
  47. hindsight_client_api/models/entity_observation_response.py +1 -1
  48. hindsight_client_api/models/entity_state_response.py +1 -1
  49. hindsight_client_api/models/features_info.py +91 -0
  50. hindsight_client_api/models/graph_data_response.py +1 -1
  51. hindsight_client_api/models/http_validation_error.py +1 -1
  52. hindsight_client_api/models/include_options.py +1 -1
  53. hindsight_client_api/models/list_documents_response.py +1 -1
  54. hindsight_client_api/models/list_memory_units_response.py +1 -1
  55. hindsight_client_api/models/list_tags_response.py +1 -1
  56. hindsight_client_api/models/memory_item.py +1 -1
  57. hindsight_client_api/models/mental_model_list_response.py +95 -0
  58. hindsight_client_api/models/mental_model_response.py +126 -0
  59. hindsight_client_api/models/mental_model_trigger.py +87 -0
  60. hindsight_client_api/models/operation_response.py +2 -2
  61. hindsight_client_api/models/operation_status_response.py +131 -0
  62. hindsight_client_api/models/operations_list_response.py +9 -3
  63. hindsight_client_api/models/recall_request.py +1 -1
  64. hindsight_client_api/models/recall_response.py +1 -1
  65. hindsight_client_api/models/recall_result.py +1 -1
  66. hindsight_client_api/models/reflect_based_on.py +115 -0
  67. hindsight_client_api/models/reflect_directive.py +91 -0
  68. hindsight_client_api/models/reflect_fact.py +1 -1
  69. hindsight_client_api/models/reflect_include_options.py +14 -3
  70. hindsight_client_api/models/reflect_llm_call.py +89 -0
  71. hindsight_client_api/models/reflect_mental_model.py +96 -0
  72. hindsight_client_api/models/reflect_request.py +1 -1
  73. hindsight_client_api/models/reflect_response.py +24 -12
  74. hindsight_client_api/models/reflect_tool_call.py +100 -0
  75. hindsight_client_api/models/reflect_trace.py +105 -0
  76. hindsight_client_api/models/retain_request.py +1 -1
  77. hindsight_client_api/models/retain_response.py +1 -1
  78. hindsight_client_api/models/tag_item.py +1 -1
  79. hindsight_client_api/models/token_usage.py +1 -1
  80. hindsight_client_api/models/tool_calls_include_options.py +87 -0
  81. hindsight_client_api/models/update_directive_request.py +120 -0
  82. hindsight_client_api/models/update_disposition_request.py +1 -1
  83. hindsight_client_api/models/update_mental_model_request.py +125 -0
  84. hindsight_client_api/models/validation_error.py +1 -1
  85. hindsight_client_api/models/validation_error_loc_inner.py +1 -1
  86. hindsight_client_api/models/version_response.py +93 -0
  87. hindsight_client_api/rest.py +1 -1
  88. hindsight_client-0.3.0.dist-info/RECORD +0 -65
  89. {hindsight_client-0.3.0.dist-info → hindsight_client-0.4.1.dist-info}/WHEEL +0 -0
@@ -6,23 +6,23 @@ easy-to-use interface on top of the auto-generated OpenAPI client.
6
6
  """
7
7
 
8
8
  import asyncio
9
- from typing import Optional, List, Dict, Any
10
9
  from datetime import datetime
10
+ from typing import Any, Literal
11
11
 
12
12
  import hindsight_client_api
13
- from hindsight_client_api.api import memory_api, banks_api
13
+ from hindsight_client_api.api import banks_api, directives_api, memory_api, mental_models_api
14
14
  from hindsight_client_api.models import (
15
- recall_request,
16
- retain_request,
17
15
  memory_item,
16
+ recall_request,
18
17
  reflect_request,
18
+ retain_request,
19
19
  )
20
- from hindsight_client_api.models.retain_response import RetainResponse
20
+ from hindsight_client_api.models.bank_profile_response import BankProfileResponse
21
+ from hindsight_client_api.models.list_memory_units_response import ListMemoryUnitsResponse
21
22
  from hindsight_client_api.models.recall_response import RecallResponse
22
23
  from hindsight_client_api.models.recall_result import RecallResult
23
24
  from hindsight_client_api.models.reflect_response import ReflectResponse
24
- from hindsight_client_api.models.list_memory_units_response import ListMemoryUnitsResponse
25
- from hindsight_client_api.models.bank_profile_response import BankProfileResponse
25
+ from hindsight_client_api.models.retain_response import RetainResponse
26
26
 
27
27
 
28
28
  def _run_async(coro):
@@ -63,7 +63,7 @@ class Hindsight:
63
63
  ```
64
64
  """
65
65
 
66
- def __init__(self, base_url: str, api_key: Optional[str] = None, timeout: float = 30.0):
66
+ def __init__(self, base_url: str, api_key: str | None = None, timeout: float = 30.0):
67
67
  """
68
68
  Initialize the Hindsight client.
69
69
 
@@ -78,6 +78,8 @@ class Hindsight:
78
78
  self._api_client.set_default_header("Authorization", f"Bearer {api_key}")
79
79
  self._memory_api = memory_api.MemoryApi(self._api_client)
80
80
  self._banks_api = banks_api.BanksApi(self._api_client)
81
+ self._mental_models_api = mental_models_api.MentalModelsApi(self._api_client)
82
+ self._directives_api = directives_api.DirectivesApi(self._api_client)
81
83
 
82
84
  def __enter__(self):
83
85
  """Context manager entry."""
@@ -110,11 +112,12 @@ class Hindsight:
110
112
  self,
111
113
  bank_id: str,
112
114
  content: str,
113
- timestamp: Optional[datetime] = None,
114
- context: Optional[str] = None,
115
- document_id: Optional[str] = None,
116
- metadata: Optional[Dict[str, str]] = None,
117
- entities: Optional[List[Dict[str, str]]] = None,
115
+ timestamp: datetime | None = None,
116
+ context: str | None = None,
117
+ document_id: str | None = None,
118
+ metadata: dict[str, str] | None = None,
119
+ entities: list[dict[str, str]] | None = None,
120
+ tags: list[str] | None = None,
118
121
  ) -> RetainResponse:
119
122
  """
120
123
  Store a single memory (simplified interface).
@@ -127,21 +130,32 @@ class Hindsight:
127
130
  document_id: Optional document ID for grouping
128
131
  metadata: Optional user-defined metadata
129
132
  entities: Optional list of entities [{"text": "...", "type": "..."}]
133
+ tags: Optional list of tags for filtering memories during recall/reflect
130
134
 
131
135
  Returns:
132
136
  RetainResponse with success status
133
137
  """
134
138
  return self.retain_batch(
135
139
  bank_id=bank_id,
136
- items=[{"content": content, "timestamp": timestamp, "context": context, "metadata": metadata, "entities": entities}],
140
+ items=[
141
+ {
142
+ "content": content,
143
+ "timestamp": timestamp,
144
+ "context": context,
145
+ "metadata": metadata,
146
+ "entities": entities,
147
+ "tags": tags,
148
+ }
149
+ ],
137
150
  document_id=document_id,
138
151
  )
139
152
 
140
153
  def retain_batch(
141
154
  self,
142
155
  bank_id: str,
143
- items: List[Dict[str, Any]],
144
- document_id: Optional[str] = None,
156
+ items: list[dict[str, Any]],
157
+ document_id: str | None = None,
158
+ document_tags: list[str] | None = None,
145
159
  retain_async: bool = False,
146
160
  ) -> RetainResponse:
147
161
  """
@@ -149,8 +163,9 @@ class Hindsight:
149
163
 
150
164
  Args:
151
165
  bank_id: The memory bank ID
152
- items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities'
166
+ items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags'
153
167
  document_id: Optional document ID for grouping memories (applied to items that don't have their own)
168
+ document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
154
169
  retain_async: If True, process asynchronously in background (default: False)
155
170
 
156
171
  Returns:
@@ -162,10 +177,7 @@ class Hindsight:
162
177
  for item in items:
163
178
  entities = None
164
179
  if item.get("entities"):
165
- entities = [
166
- EntityInput(text=e["text"], type=e.get("type"))
167
- for e in item["entities"]
168
- ]
180
+ entities = [EntityInput(text=e["text"], type=e.get("type")) for e in item["entities"]]
169
181
  memory_items.append(
170
182
  memory_item.MemoryItem(
171
183
  content=item["content"],
@@ -175,12 +187,14 @@ class Hindsight:
175
187
  # Use item's document_id if provided, otherwise fall back to batch-level document_id
176
188
  document_id=item.get("document_id") or document_id,
177
189
  entities=entities,
190
+ tags=item.get("tags"),
178
191
  )
179
192
  )
180
193
 
181
194
  request_obj = retain_request.RetainRequest(
182
195
  items=memory_items,
183
196
  async_=retain_async,
197
+ document_tags=document_tags,
184
198
  )
185
199
 
186
200
  return _run_async(self._memory_api.retain_memories(bank_id, request_obj))
@@ -189,15 +203,17 @@ class Hindsight:
189
203
  self,
190
204
  bank_id: str,
191
205
  query: str,
192
- types: Optional[List[str]] = None,
206
+ types: list[str] | None = None,
193
207
  max_tokens: int = 4096,
194
208
  budget: str = "mid",
195
209
  trace: bool = False,
196
- query_timestamp: Optional[str] = None,
210
+ query_timestamp: str | None = None,
197
211
  include_entities: bool = False,
198
212
  max_entity_tokens: int = 500,
199
213
  include_chunks: bool = False,
200
214
  max_chunk_tokens: int = 8192,
215
+ tags: list[str] | None = None,
216
+ tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
201
217
  ) -> RecallResponse:
202
218
  """
203
219
  Recall memories using semantic similarity.
@@ -214,14 +230,19 @@ class Hindsight:
214
230
  max_entity_tokens: Maximum tokens for entity observations (default: 500)
215
231
  include_chunks: Include raw text chunks in results (default: False)
216
232
  max_chunk_tokens: Maximum tokens for chunks (default: 8192)
233
+ tags: Optional list of tags to filter memories by
234
+ tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
235
+ "any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
217
236
 
218
237
  Returns:
219
238
  RecallResponse with results, optional entities, optional chunks, and optional trace
220
239
  """
221
- from hindsight_client_api.models import include_options, entity_include_options, chunk_include_options
240
+ from hindsight_client_api.models import chunk_include_options, entity_include_options, include_options
222
241
 
223
242
  include_opts = include_options.IncludeOptions(
224
- entities=entity_include_options.EntityIncludeOptions(max_tokens=max_entity_tokens) if include_entities else None,
243
+ entities=entity_include_options.EntityIncludeOptions(max_tokens=max_entity_tokens)
244
+ if include_entities
245
+ else None,
225
246
  chunks=chunk_include_options.ChunkIncludeOptions(max_tokens=max_chunk_tokens) if include_chunks else None,
226
247
  )
227
248
 
@@ -233,6 +254,8 @@ class Hindsight:
233
254
  trace=trace,
234
255
  query_timestamp=query_timestamp,
235
256
  include=include_opts,
257
+ tags=tags,
258
+ tags_match=tags_match,
236
259
  )
237
260
 
238
261
  return _run_async(self._memory_api.recall_memories(bank_id, request_obj))
@@ -242,9 +265,11 @@ class Hindsight:
242
265
  bank_id: str,
243
266
  query: str,
244
267
  budget: str = "low",
245
- context: Optional[str] = None,
246
- max_tokens: Optional[int] = None,
247
- response_schema: Optional[Dict[str, Any]] = None,
268
+ context: str | None = None,
269
+ max_tokens: int | None = None,
270
+ response_schema: dict[str, Any] | None = None,
271
+ tags: list[str] | None = None,
272
+ tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
248
273
  ) -> ReflectResponse:
249
274
  """
250
275
  Generate a contextual answer based on bank identity and memories.
@@ -258,6 +283,9 @@ class Hindsight:
258
283
  response_schema: Optional JSON Schema for structured output. When provided,
259
284
  the response will include a 'structured_output' field with the LLM
260
285
  response parsed according to this schema.
286
+ tags: Optional list of tags to filter memories by
287
+ tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
288
+ "any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
261
289
 
262
290
  Returns:
263
291
  ReflectResponse with answer text, optionally facts used, and optionally
@@ -269,6 +297,8 @@ class Hindsight:
269
297
  context=context,
270
298
  max_tokens=max_tokens,
271
299
  response_schema=response_schema,
300
+ tags=tags,
301
+ tags_match=tags_match,
272
302
  )
273
303
 
274
304
  return _run_async(self._memory_api.reflect(bank_id, request_obj))
@@ -276,28 +306,37 @@ class Hindsight:
276
306
  def list_memories(
277
307
  self,
278
308
  bank_id: str,
279
- type: Optional[str] = None,
280
- search_query: Optional[str] = None,
309
+ type: str | None = None,
310
+ search_query: str | None = None,
281
311
  limit: int = 100,
282
312
  offset: int = 0,
283
313
  ) -> ListMemoryUnitsResponse:
284
314
  """List memory units with pagination."""
285
- return _run_async(self._memory_api.list_memories(
286
- bank_id=bank_id,
287
- type=type,
288
- q=search_query,
289
- limit=limit,
290
- offset=offset,
291
- ))
315
+ return _run_async(
316
+ self._memory_api.list_memories(
317
+ bank_id=bank_id,
318
+ type=type,
319
+ q=search_query,
320
+ limit=limit,
321
+ offset=offset,
322
+ )
323
+ )
292
324
 
293
325
  def create_bank(
294
326
  self,
295
327
  bank_id: str,
296
- name: Optional[str] = None,
297
- background: Optional[str] = None,
298
- disposition: Optional[Dict[str, float]] = None,
328
+ name: str | None = None,
329
+ mission: str | None = None,
330
+ disposition: dict[str, float] | None = None,
299
331
  ) -> BankProfileResponse:
300
- """Create or update a memory bank."""
332
+ """Create or update a memory bank.
333
+
334
+ Args:
335
+ bank_id: Unique identifier for the bank
336
+ name: Human-readable display name
337
+ mission: Instructions guiding what Hindsight should learn and remember (for mental models)
338
+ disposition: Optional disposition traits (skepticism, literalism, empathy)
339
+ """
301
340
  from hindsight_client_api.models import create_bank_request, disposition_traits
302
341
 
303
342
  disposition_obj = None
@@ -306,19 +345,40 @@ class Hindsight:
306
345
 
307
346
  request_obj = create_bank_request.CreateBankRequest(
308
347
  name=name,
309
- background=background,
348
+ mission=mission,
310
349
  disposition=disposition_obj,
311
350
  )
312
351
 
313
352
  return _run_async(self._banks_api.create_or_update_bank(bank_id, request_obj))
314
353
 
354
+ def set_mission(
355
+ self,
356
+ bank_id: str,
357
+ mission: str,
358
+ ) -> BankProfileResponse:
359
+ """
360
+ Set or update the mission for a memory bank.
361
+
362
+ Args:
363
+ bank_id: The memory bank ID
364
+ mission: The mission text describing the agent's purpose
365
+
366
+ Returns:
367
+ BankProfileResponse with updated bank profile
368
+ """
369
+ from hindsight_client_api.models import create_bank_request
370
+
371
+ request_obj = create_bank_request.CreateBankRequest(mission=mission)
372
+ return _run_async(self._banks_api.create_or_update_bank(bank_id, request_obj))
373
+
315
374
  # Async methods (native async, no _run_async wrapper)
316
375
 
317
376
  async def aretain_batch(
318
377
  self,
319
378
  bank_id: str,
320
- items: List[Dict[str, Any]],
321
- document_id: Optional[str] = None,
379
+ items: list[dict[str, Any]],
380
+ document_id: str | None = None,
381
+ document_tags: list[str] | None = None,
322
382
  retain_async: bool = False,
323
383
  ) -> RetainResponse:
324
384
  """
@@ -326,8 +386,9 @@ class Hindsight:
326
386
 
327
387
  Args:
328
388
  bank_id: The memory bank ID
329
- items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities'
389
+ items: List of memory items with 'content' and optional 'timestamp', 'context', 'metadata', 'document_id', 'entities', 'tags'
330
390
  document_id: Optional document ID for grouping memories (applied to items that don't have their own)
391
+ document_tags: Optional list of tags applied to all items in this batch (merged with per-item tags)
331
392
  retain_async: If True, process asynchronously in background (default: False)
332
393
 
333
394
  Returns:
@@ -339,10 +400,7 @@ class Hindsight:
339
400
  for item in items:
340
401
  entities = None
341
402
  if item.get("entities"):
342
- entities = [
343
- EntityInput(text=e["text"], type=e.get("type"))
344
- for e in item["entities"]
345
- ]
403
+ entities = [EntityInput(text=e["text"], type=e.get("type")) for e in item["entities"]]
346
404
  memory_items.append(
347
405
  memory_item.MemoryItem(
348
406
  content=item["content"],
@@ -352,12 +410,14 @@ class Hindsight:
352
410
  # Use item's document_id if provided, otherwise fall back to batch-level document_id
353
411
  document_id=item.get("document_id") or document_id,
354
412
  entities=entities,
413
+ tags=item.get("tags"),
355
414
  )
356
415
  )
357
416
 
358
417
  request_obj = retain_request.RetainRequest(
359
418
  items=memory_items,
360
419
  async_=retain_async,
420
+ document_tags=document_tags,
361
421
  )
362
422
 
363
423
  return await self._memory_api.retain_memories(bank_id, request_obj)
@@ -366,11 +426,12 @@ class Hindsight:
366
426
  self,
367
427
  bank_id: str,
368
428
  content: str,
369
- timestamp: Optional[datetime] = None,
370
- context: Optional[str] = None,
371
- document_id: Optional[str] = None,
372
- metadata: Optional[Dict[str, str]] = None,
373
- entities: Optional[List[Dict[str, str]]] = None,
429
+ timestamp: datetime | None = None,
430
+ context: str | None = None,
431
+ document_id: str | None = None,
432
+ metadata: dict[str, str] | None = None,
433
+ entities: list[dict[str, str]] | None = None,
434
+ tags: list[str] | None = None,
374
435
  ) -> RetainResponse:
375
436
  """
376
437
  Store a single memory (async).
@@ -383,13 +444,23 @@ class Hindsight:
383
444
  document_id: Optional document ID for grouping
384
445
  metadata: Optional user-defined metadata
385
446
  entities: Optional list of entities [{"text": "...", "type": "..."}]
447
+ tags: Optional list of tags for filtering memories during recall/reflect
386
448
 
387
449
  Returns:
388
450
  RetainResponse with success status
389
451
  """
390
452
  return await self.aretain_batch(
391
453
  bank_id=bank_id,
392
- items=[{"content": content, "timestamp": timestamp, "context": context, "metadata": metadata, "entities": entities}],
454
+ items=[
455
+ {
456
+ "content": content,
457
+ "timestamp": timestamp,
458
+ "context": context,
459
+ "metadata": metadata,
460
+ "entities": entities,
461
+ "tags": tags,
462
+ }
463
+ ],
393
464
  document_id=document_id,
394
465
  )
395
466
 
@@ -397,10 +468,12 @@ class Hindsight:
397
468
  self,
398
469
  bank_id: str,
399
470
  query: str,
400
- types: Optional[List[str]] = None,
471
+ types: list[str] | None = None,
401
472
  max_tokens: int = 4096,
402
473
  budget: str = "mid",
403
- ) -> List[RecallResult]:
474
+ tags: list[str] | None = None,
475
+ tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
476
+ ) -> list[RecallResult]:
404
477
  """
405
478
  Recall memories using semantic similarity (async).
406
479
 
@@ -410,6 +483,9 @@ class Hindsight:
410
483
  types: Optional list of fact types to filter (world, experience, opinion, observation)
411
484
  max_tokens: Maximum tokens in results (default: 4096)
412
485
  budget: Budget level for recall - "low", "mid", or "high" (default: "mid")
486
+ tags: Optional list of tags to filter memories by
487
+ tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
488
+ "any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
413
489
 
414
490
  Returns:
415
491
  List of RecallResult objects
@@ -420,17 +496,21 @@ class Hindsight:
420
496
  budget=budget,
421
497
  max_tokens=max_tokens,
422
498
  trace=False,
499
+ tags=tags,
500
+ tags_match=tags_match,
423
501
  )
424
502
 
425
503
  response = await self._memory_api.recall_memories(bank_id, request_obj)
426
- return response.results if hasattr(response, 'results') else []
504
+ return response.results if hasattr(response, "results") else []
427
505
 
428
506
  async def areflect(
429
507
  self,
430
508
  bank_id: str,
431
509
  query: str,
432
510
  budget: str = "low",
433
- context: Optional[str] = None,
511
+ context: str | None = None,
512
+ tags: list[str] | None = None,
513
+ tags_match: Literal["any", "all", "any_strict", "all_strict"] = "any",
434
514
  ) -> ReflectResponse:
435
515
  """
436
516
  Generate a contextual answer based on bank identity and memories (async).
@@ -440,6 +520,9 @@ class Hindsight:
440
520
  query: The question or prompt
441
521
  budget: Budget level for reflection - "low", "mid", or "high" (default: "low")
442
522
  context: Optional additional context
523
+ tags: Optional list of tags to filter memories by
524
+ tags_match: How to match tags - "any" (OR, includes untagged), "all" (AND, includes untagged),
525
+ "any_strict" (OR, excludes untagged), "all_strict" (AND, excludes untagged). Default: "any"
443
526
 
444
527
  Returns:
445
528
  ReflectResponse with answer text and optionally facts used
@@ -448,6 +531,258 @@ class Hindsight:
448
531
  query=query,
449
532
  budget=budget,
450
533
  context=context,
534
+ tags=tags,
535
+ tags_match=tags_match,
451
536
  )
452
537
 
453
538
  return await self._memory_api.reflect(bank_id, request_obj)
539
+
540
+ # Mental Models methods
541
+
542
+ def create_mental_model(
543
+ self,
544
+ bank_id: str,
545
+ name: str,
546
+ source_query: str,
547
+ tags: list[str] | None = None,
548
+ max_tokens: int | None = None,
549
+ trigger: dict[str, Any] | None = None,
550
+ ):
551
+ """
552
+ Create a mental model (runs reflect in background).
553
+
554
+ Args:
555
+ bank_id: The memory bank ID
556
+ name: Human-readable name for the mental model
557
+ source_query: The query to run to generate content
558
+ tags: Optional tags for filtering during retrieval
559
+ max_tokens: Optional maximum tokens for the mental model content
560
+ trigger: Optional trigger settings (e.g., {"refresh_after_consolidation": True})
561
+
562
+ Returns:
563
+ CreateMentalModelResponse with operation_id
564
+ """
565
+ from hindsight_client_api.models import create_mental_model_request, mental_model_trigger
566
+
567
+ trigger_obj = None
568
+ if trigger:
569
+ trigger_obj = mental_model_trigger.MentalModelTrigger(**trigger)
570
+
571
+ request_obj = create_mental_model_request.CreateMentalModelRequest(
572
+ name=name,
573
+ source_query=source_query,
574
+ tags=tags,
575
+ max_tokens=max_tokens,
576
+ trigger=trigger_obj,
577
+ )
578
+
579
+ return _run_async(self._mental_models_api.create_mental_model(bank_id, request_obj))
580
+
581
+ def list_mental_models(self, bank_id: str, tags: list[str] | None = None):
582
+ """
583
+ List all mental models in a bank.
584
+
585
+ Args:
586
+ bank_id: The memory bank ID
587
+ tags: Optional tags to filter by
588
+
589
+ Returns:
590
+ ListMentalModelsResponse with items
591
+ """
592
+ return _run_async(self._mental_models_api.list_mental_models(bank_id, tags=tags))
593
+
594
+ def get_mental_model(self, bank_id: str, mental_model_id: str):
595
+ """
596
+ Get a specific mental model.
597
+
598
+ Args:
599
+ bank_id: The memory bank ID
600
+ mental_model_id: The mental model ID
601
+
602
+ Returns:
603
+ MentalModelResponse
604
+ """
605
+ return _run_async(self._mental_models_api.get_mental_model(bank_id, mental_model_id))
606
+
607
+ def refresh_mental_model(self, bank_id: str, mental_model_id: str):
608
+ """
609
+ Refresh a mental model to update with current knowledge.
610
+
611
+ Args:
612
+ bank_id: The memory bank ID
613
+ mental_model_id: The mental model ID
614
+
615
+ Returns:
616
+ RefreshMentalModelResponse with operation_id
617
+ """
618
+ return _run_async(self._mental_models_api.refresh_mental_model(bank_id, mental_model_id))
619
+
620
+ def update_mental_model(
621
+ self,
622
+ bank_id: str,
623
+ mental_model_id: str,
624
+ name: str | None = None,
625
+ source_query: str | None = None,
626
+ tags: list[str] | None = None,
627
+ max_tokens: int | None = None,
628
+ trigger: dict[str, Any] | None = None,
629
+ ):
630
+ """
631
+ Update a mental model's metadata.
632
+
633
+ Args:
634
+ bank_id: The memory bank ID
635
+ mental_model_id: The mental model ID
636
+ name: Optional new name
637
+ source_query: Optional new source query
638
+ tags: Optional new tags
639
+ max_tokens: Optional new max tokens
640
+ trigger: Optional trigger settings (e.g., {"refresh_after_consolidation": True})
641
+
642
+ Returns:
643
+ MentalModelResponse
644
+ """
645
+ from hindsight_client_api.models import mental_model_trigger, update_mental_model_request
646
+
647
+ trigger_obj = None
648
+ if trigger:
649
+ trigger_obj = mental_model_trigger.MentalModelTrigger(**trigger)
650
+
651
+ request_obj = update_mental_model_request.UpdateMentalModelRequest(
652
+ name=name,
653
+ source_query=source_query,
654
+ tags=tags,
655
+ max_tokens=max_tokens,
656
+ trigger=trigger_obj,
657
+ )
658
+
659
+ return _run_async(self._mental_models_api.update_mental_model(bank_id, mental_model_id, request_obj))
660
+
661
+ def delete_mental_model(self, bank_id: str, mental_model_id: str):
662
+ """
663
+ Delete a mental model.
664
+
665
+ Args:
666
+ bank_id: The memory bank ID
667
+ mental_model_id: The mental model ID
668
+ """
669
+ return _run_async(self._mental_models_api.delete_mental_model(bank_id, mental_model_id))
670
+
671
+ # Directives methods
672
+
673
+ def create_directive(
674
+ self,
675
+ bank_id: str,
676
+ name: str,
677
+ content: str,
678
+ priority: int = 0,
679
+ is_active: bool = True,
680
+ tags: list[str] | None = None,
681
+ ):
682
+ """
683
+ Create a directive (hard rule for reflect).
684
+
685
+ Args:
686
+ bank_id: The memory bank ID
687
+ name: Human-readable name for the directive
688
+ content: The directive content/rules
689
+ priority: Priority level (higher = injected first)
690
+ is_active: Whether the directive is active
691
+ tags: Optional tags for filtering
692
+
693
+ Returns:
694
+ DirectiveResponse
695
+ """
696
+ from hindsight_client_api.models import create_directive_request
697
+
698
+ request_obj = create_directive_request.CreateDirectiveRequest(
699
+ name=name,
700
+ content=content,
701
+ priority=priority,
702
+ is_active=is_active,
703
+ tags=tags,
704
+ )
705
+
706
+ return _run_async(self._directives_api.create_directive(bank_id, request_obj))
707
+
708
+ def list_directives(self, bank_id: str, tags: list[str] | None = None):
709
+ """
710
+ List all directives in a bank.
711
+
712
+ Args:
713
+ bank_id: The memory bank ID
714
+ tags: Optional tags to filter by
715
+
716
+ Returns:
717
+ ListDirectivesResponse with items
718
+ """
719
+ return _run_async(self._directives_api.list_directives(bank_id, tags=tags))
720
+
721
+ def get_directive(self, bank_id: str, directive_id: str):
722
+ """
723
+ Get a specific directive.
724
+
725
+ Args:
726
+ bank_id: The memory bank ID
727
+ directive_id: The directive ID
728
+
729
+ Returns:
730
+ DirectiveResponse
731
+ """
732
+ return _run_async(self._directives_api.get_directive(bank_id, directive_id))
733
+
734
+ def update_directive(
735
+ self,
736
+ bank_id: str,
737
+ directive_id: str,
738
+ name: str | None = None,
739
+ content: str | None = None,
740
+ priority: int | None = None,
741
+ is_active: bool | None = None,
742
+ tags: list[str] | None = None,
743
+ ):
744
+ """
745
+ Update a directive.
746
+
747
+ Args:
748
+ bank_id: The memory bank ID
749
+ directive_id: The directive ID
750
+ name: Optional new name
751
+ content: Optional new content
752
+ priority: Optional new priority
753
+ is_active: Optional new active status
754
+ tags: Optional new tags
755
+
756
+ Returns:
757
+ DirectiveResponse
758
+ """
759
+ from hindsight_client_api.models import update_directive_request
760
+
761
+ request_obj = update_directive_request.UpdateDirectiveRequest(
762
+ name=name,
763
+ content=content,
764
+ priority=priority,
765
+ is_active=is_active,
766
+ tags=tags,
767
+ )
768
+
769
+ return _run_async(self._directives_api.update_directive(bank_id, directive_id, request_obj))
770
+
771
+ def delete_directive(self, bank_id: str, directive_id: str):
772
+ """
773
+ Delete a directive.
774
+
775
+ Args:
776
+ bank_id: The memory bank ID
777
+ directive_id: The directive ID
778
+ """
779
+ return _run_async(self._directives_api.delete_directive(bank_id, directive_id))
780
+
781
+ def delete_bank(self, bank_id: str):
782
+ """
783
+ Delete a memory bank.
784
+
785
+ Args:
786
+ bank_id: The memory bank ID
787
+ """
788
+ return _run_async(self._banks_api.delete_bank(bank_id))