hindsight-api 0.1.16__py3-none-any.whl → 0.2.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.
- hindsight_api/api/__init__.py +38 -14
- hindsight_api/api/http.py +100 -9
- hindsight_api/api/mcp.py +203 -52
- hindsight_api/config.py +27 -0
- hindsight_api/engine/interface.py +4 -0
- hindsight_api/engine/llm_wrapper.py +275 -45
- hindsight_api/engine/memory_engine.py +69 -16
- hindsight_api/engine/response_models.py +7 -1
- hindsight_api/engine/retain/entity_processing.py +37 -8
- hindsight_api/engine/retain/fact_extraction.py +49 -6
- hindsight_api/engine/retain/observation_regeneration.py +4 -2
- hindsight_api/engine/retain/orchestrator.py +12 -1
- hindsight_api/engine/retain/types.py +7 -0
- hindsight_api/extensions/context.py +8 -1
- hindsight_api/extensions/operation_validator.py +6 -4
- hindsight_api/main.py +29 -1
- hindsight_api/models.py +3 -0
- {hindsight_api-0.1.16.dist-info → hindsight_api-0.2.0.dist-info}/METADATA +3 -2
- {hindsight_api-0.1.16.dist-info → hindsight_api-0.2.0.dist-info}/RECORD +21 -21
- {hindsight_api-0.1.16.dist-info → hindsight_api-0.2.0.dist-info}/WHEEL +0 -0
- {hindsight_api-0.1.16.dist-info → hindsight_api-0.2.0.dist-info}/entry_points.txt +0 -0
hindsight_api/api/__init__.py
CHANGED
|
@@ -5,6 +5,7 @@ Provides both HTTP REST API and MCP (Model Context Protocol) server.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import logging
|
|
8
|
+
from contextlib import asynccontextmanager
|
|
8
9
|
from typing import Optional
|
|
9
10
|
|
|
10
11
|
from fastapi import FastAPI
|
|
@@ -45,6 +46,18 @@ def create_app(
|
|
|
45
46
|
# Both HTTP and MCP
|
|
46
47
|
app = create_app(memory, mcp_api_enabled=True)
|
|
47
48
|
"""
|
|
49
|
+
mcp_app = None
|
|
50
|
+
|
|
51
|
+
# Create MCP app first if enabled (we need its lifespan for chaining)
|
|
52
|
+
if mcp_api_enabled:
|
|
53
|
+
try:
|
|
54
|
+
from .mcp import create_mcp_app
|
|
55
|
+
|
|
56
|
+
mcp_app = create_mcp_app(memory=memory)
|
|
57
|
+
except ImportError as e:
|
|
58
|
+
logger.error(f"MCP server requested but dependencies not available: {e}")
|
|
59
|
+
logger.error("Install with: pip install hindsight-api[mcp]")
|
|
60
|
+
raise
|
|
48
61
|
|
|
49
62
|
# Import and create HTTP API if enabled
|
|
50
63
|
if http_api_enabled:
|
|
@@ -57,20 +70,31 @@ def create_app(
|
|
|
57
70
|
app = FastAPI(title="Hindsight API", version="0.0.7")
|
|
58
71
|
logger.info("HTTP REST API disabled")
|
|
59
72
|
|
|
60
|
-
# Mount MCP server if enabled
|
|
61
|
-
if
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
# Mount MCP server and chain its lifespan if enabled
|
|
74
|
+
if mcp_app is not None:
|
|
75
|
+
# Get the MCP app's underlying Starlette app for lifespan access
|
|
76
|
+
mcp_starlette_app = mcp_app.mcp_app
|
|
77
|
+
|
|
78
|
+
# Store the original lifespan
|
|
79
|
+
original_lifespan = app.router.lifespan_context
|
|
80
|
+
|
|
81
|
+
@asynccontextmanager
|
|
82
|
+
async def chained_lifespan(app_instance: FastAPI):
|
|
83
|
+
"""Chain the MCP lifespan with the main app lifespan."""
|
|
84
|
+
# Start MCP lifespan first
|
|
85
|
+
async with mcp_starlette_app.router.lifespan_context(mcp_starlette_app):
|
|
86
|
+
logger.info("MCP lifespan started")
|
|
87
|
+
# Then start the original app lifespan
|
|
88
|
+
async with original_lifespan(app_instance):
|
|
89
|
+
yield
|
|
90
|
+
logger.info("MCP lifespan stopped")
|
|
91
|
+
|
|
92
|
+
# Replace the app's lifespan with the chained version
|
|
93
|
+
app.router.lifespan_context = chained_lifespan
|
|
94
|
+
|
|
95
|
+
# Mount the MCP middleware
|
|
96
|
+
app.mount(mcp_mount_path, mcp_app)
|
|
97
|
+
logger.info(f"MCP server enabled at {mcp_mount_path}/")
|
|
74
98
|
|
|
75
99
|
return app
|
|
76
100
|
|
hindsight_api/api/http.py
CHANGED
|
@@ -14,6 +14,8 @@ from typing import Any
|
|
|
14
14
|
|
|
15
15
|
from fastapi import Depends, FastAPI, Header, HTTPException, Query
|
|
16
16
|
|
|
17
|
+
from hindsight_api.extensions import AuthenticationError
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
def _parse_metadata(metadata: Any) -> dict[str, Any]:
|
|
19
21
|
"""Parse metadata that may be a dict, JSON string, or None."""
|
|
@@ -35,7 +37,7 @@ from hindsight_api import MemoryEngine
|
|
|
35
37
|
from hindsight_api.engine.db_utils import acquire_with_retry
|
|
36
38
|
from hindsight_api.engine.memory_engine import Budget, fq_table
|
|
37
39
|
from hindsight_api.engine.response_models import VALID_RECALL_FACT_TYPES
|
|
38
|
-
from hindsight_api.extensions import HttpExtension, load_extension
|
|
40
|
+
from hindsight_api.extensions import HttpExtension, OperationValidationError, load_extension
|
|
39
41
|
from hindsight_api.metrics import create_metrics_collector, get_metrics_collector, initialize_metrics
|
|
40
42
|
from hindsight_api.models import RequestContext
|
|
41
43
|
|
|
@@ -279,6 +281,13 @@ class RecallResponse(BaseModel):
|
|
|
279
281
|
chunks: dict[str, ChunkData] | None = Field(default=None, description="Chunks for facts, keyed by chunk_id")
|
|
280
282
|
|
|
281
283
|
|
|
284
|
+
class EntityInput(BaseModel):
|
|
285
|
+
"""Entity to associate with retained content."""
|
|
286
|
+
|
|
287
|
+
text: str = Field(description="The entity name/text")
|
|
288
|
+
type: str | None = Field(default=None, description="Optional entity type (e.g., 'PERSON', 'ORG', 'CONCEPT')")
|
|
289
|
+
|
|
290
|
+
|
|
282
291
|
class MemoryItem(BaseModel):
|
|
283
292
|
"""Single memory item for retain."""
|
|
284
293
|
|
|
@@ -290,6 +299,7 @@ class MemoryItem(BaseModel):
|
|
|
290
299
|
"context": "team meeting",
|
|
291
300
|
"metadata": {"source": "slack", "channel": "engineering"},
|
|
292
301
|
"document_id": "meeting_notes_2024_01_15",
|
|
302
|
+
"entities": [{"text": "Alice"}, {"text": "ML model", "type": "CONCEPT"}],
|
|
293
303
|
}
|
|
294
304
|
},
|
|
295
305
|
)
|
|
@@ -299,6 +309,10 @@ class MemoryItem(BaseModel):
|
|
|
299
309
|
context: str | None = None
|
|
300
310
|
metadata: dict[str, str] | None = None
|
|
301
311
|
document_id: str | None = Field(default=None, description="Optional document ID for this memory item.")
|
|
312
|
+
entities: list[EntityInput] | None = Field(
|
|
313
|
+
default=None,
|
|
314
|
+
description="Optional entities to combine with auto-extracted entities.",
|
|
315
|
+
)
|
|
302
316
|
|
|
303
317
|
@field_validator("timestamp", mode="before")
|
|
304
318
|
@classmethod
|
|
@@ -385,7 +399,16 @@ class ReflectRequest(BaseModel):
|
|
|
385
399
|
"query": "What do you think about artificial intelligence?",
|
|
386
400
|
"budget": "low",
|
|
387
401
|
"context": "This is for a research paper on AI ethics",
|
|
402
|
+
"max_tokens": 4096,
|
|
388
403
|
"include": {"facts": {}},
|
|
404
|
+
"response_schema": {
|
|
405
|
+
"type": "object",
|
|
406
|
+
"properties": {
|
|
407
|
+
"summary": {"type": "string"},
|
|
408
|
+
"key_points": {"type": "array", "items": {"type": "string"}},
|
|
409
|
+
},
|
|
410
|
+
"required": ["summary", "key_points"],
|
|
411
|
+
},
|
|
389
412
|
}
|
|
390
413
|
}
|
|
391
414
|
)
|
|
@@ -393,9 +416,14 @@ class ReflectRequest(BaseModel):
|
|
|
393
416
|
query: str
|
|
394
417
|
budget: Budget = Budget.LOW
|
|
395
418
|
context: str | None = None
|
|
419
|
+
max_tokens: int = Field(default=4096, description="Maximum tokens for the response")
|
|
396
420
|
include: ReflectIncludeOptions = Field(
|
|
397
421
|
default_factory=ReflectIncludeOptions, description="Options for including additional data (disabled by default)"
|
|
398
422
|
)
|
|
423
|
+
response_schema: dict | None = Field(
|
|
424
|
+
default=None,
|
|
425
|
+
description="Optional JSON Schema for structured output. When provided, the response will include a 'structured_output' field with the LLM response parsed according to this schema.",
|
|
426
|
+
)
|
|
399
427
|
|
|
400
428
|
|
|
401
429
|
class OpinionItem(BaseModel):
|
|
@@ -440,12 +468,20 @@ class ReflectResponse(BaseModel):
|
|
|
440
468
|
{"id": "123", "text": "AI is used in healthcare", "type": "world"},
|
|
441
469
|
{"id": "456", "text": "I discussed AI applications last week", "type": "experience"},
|
|
442
470
|
],
|
|
471
|
+
"structured_output": {
|
|
472
|
+
"summary": "AI is transformative",
|
|
473
|
+
"key_points": ["Used in healthcare", "Discussed recently"],
|
|
474
|
+
},
|
|
443
475
|
}
|
|
444
476
|
}
|
|
445
477
|
)
|
|
446
478
|
|
|
447
479
|
text: str
|
|
448
480
|
based_on: list[ReflectFact] = [] # Facts used to generate the response
|
|
481
|
+
structured_output: dict | None = Field(
|
|
482
|
+
default=None,
|
|
483
|
+
description="Structured output parsed according to the request's response_schema. Only present when response_schema was provided in the request.",
|
|
484
|
+
)
|
|
449
485
|
|
|
450
486
|
|
|
451
487
|
class BanksResponse(BaseModel):
|
|
@@ -967,6 +1003,16 @@ def _register_routes(app: FastAPI):
|
|
|
967
1003
|
api_key = authorization.strip()
|
|
968
1004
|
return RequestContext(api_key=api_key)
|
|
969
1005
|
|
|
1006
|
+
# Global exception handler for authentication errors
|
|
1007
|
+
@app.exception_handler(AuthenticationError)
|
|
1008
|
+
async def authentication_error_handler(request, exc: AuthenticationError):
|
|
1009
|
+
from fastapi.responses import JSONResponse
|
|
1010
|
+
|
|
1011
|
+
return JSONResponse(
|
|
1012
|
+
status_code=401,
|
|
1013
|
+
content={"detail": str(exc)},
|
|
1014
|
+
)
|
|
1015
|
+
|
|
970
1016
|
@app.get(
|
|
971
1017
|
"/health",
|
|
972
1018
|
summary="Health check endpoint",
|
|
@@ -1014,6 +1060,8 @@ def _register_routes(app: FastAPI):
|
|
|
1014
1060
|
try:
|
|
1015
1061
|
data = await app.state.memory.get_graph_data(bank_id, type, request_context=request_context)
|
|
1016
1062
|
return data
|
|
1063
|
+
except (AuthenticationError, HTTPException):
|
|
1064
|
+
raise
|
|
1017
1065
|
except Exception as e:
|
|
1018
1066
|
import traceback
|
|
1019
1067
|
|
|
@@ -1060,6 +1108,8 @@ def _register_routes(app: FastAPI):
|
|
|
1060
1108
|
request_context=request_context,
|
|
1061
1109
|
)
|
|
1062
1110
|
return data
|
|
1111
|
+
except (AuthenticationError, HTTPException):
|
|
1112
|
+
raise
|
|
1063
1113
|
except Exception as e:
|
|
1064
1114
|
import traceback
|
|
1065
1115
|
|
|
@@ -1176,6 +1226,10 @@ def _register_routes(app: FastAPI):
|
|
|
1176
1226
|
)
|
|
1177
1227
|
except HTTPException:
|
|
1178
1228
|
raise
|
|
1229
|
+
except OperationValidationError as e:
|
|
1230
|
+
raise HTTPException(status_code=e.status_code, detail=e.reason)
|
|
1231
|
+
except (AuthenticationError, HTTPException):
|
|
1232
|
+
raise
|
|
1179
1233
|
except Exception as e:
|
|
1180
1234
|
import traceback
|
|
1181
1235
|
|
|
@@ -1211,6 +1265,8 @@ def _register_routes(app: FastAPI):
|
|
|
1211
1265
|
query=request.query,
|
|
1212
1266
|
budget=request.budget,
|
|
1213
1267
|
context=request.context,
|
|
1268
|
+
max_tokens=request.max_tokens,
|
|
1269
|
+
response_schema=request.response_schema,
|
|
1214
1270
|
request_context=request_context,
|
|
1215
1271
|
)
|
|
1216
1272
|
|
|
@@ -1233,8 +1289,13 @@ def _register_routes(app: FastAPI):
|
|
|
1233
1289
|
return ReflectResponse(
|
|
1234
1290
|
text=core_result.text,
|
|
1235
1291
|
based_on=based_on_facts,
|
|
1292
|
+
structured_output=core_result.structured_output,
|
|
1236
1293
|
)
|
|
1237
1294
|
|
|
1295
|
+
except OperationValidationError as e:
|
|
1296
|
+
raise HTTPException(status_code=e.status_code, detail=e.reason)
|
|
1297
|
+
except (AuthenticationError, HTTPException):
|
|
1298
|
+
raise
|
|
1238
1299
|
except Exception as e:
|
|
1239
1300
|
import traceback
|
|
1240
1301
|
|
|
@@ -1255,6 +1316,8 @@ def _register_routes(app: FastAPI):
|
|
|
1255
1316
|
try:
|
|
1256
1317
|
banks = await app.state.memory.list_banks(request_context=request_context)
|
|
1257
1318
|
return BankListResponse(banks=banks)
|
|
1319
|
+
except (AuthenticationError, HTTPException):
|
|
1320
|
+
raise
|
|
1258
1321
|
except Exception as e:
|
|
1259
1322
|
import traceback
|
|
1260
1323
|
|
|
@@ -1378,6 +1441,8 @@ def _register_routes(app: FastAPI):
|
|
|
1378
1441
|
failed_operations=failed_operations,
|
|
1379
1442
|
)
|
|
1380
1443
|
|
|
1444
|
+
except (AuthenticationError, HTTPException):
|
|
1445
|
+
raise
|
|
1381
1446
|
except Exception as e:
|
|
1382
1447
|
import traceback
|
|
1383
1448
|
|
|
@@ -1402,6 +1467,8 @@ def _register_routes(app: FastAPI):
|
|
|
1402
1467
|
try:
|
|
1403
1468
|
entities = await app.state.memory.list_entities(bank_id, limit=limit, request_context=request_context)
|
|
1404
1469
|
return EntityListResponse(items=[EntityListItem(**e) for e in entities])
|
|
1470
|
+
except (AuthenticationError, HTTPException):
|
|
1471
|
+
raise
|
|
1405
1472
|
except Exception as e:
|
|
1406
1473
|
import traceback
|
|
1407
1474
|
|
|
@@ -1439,7 +1506,7 @@ def _register_routes(app: FastAPI):
|
|
|
1439
1506
|
for obs in entity["observations"]
|
|
1440
1507
|
],
|
|
1441
1508
|
)
|
|
1442
|
-
except HTTPException:
|
|
1509
|
+
except (AuthenticationError, HTTPException):
|
|
1443
1510
|
raise
|
|
1444
1511
|
except Exception as e:
|
|
1445
1512
|
import traceback
|
|
@@ -1492,7 +1559,7 @@ def _register_routes(app: FastAPI):
|
|
|
1492
1559
|
for obs in entity["observations"]
|
|
1493
1560
|
],
|
|
1494
1561
|
)
|
|
1495
|
-
except HTTPException:
|
|
1562
|
+
except (AuthenticationError, HTTPException):
|
|
1496
1563
|
raise
|
|
1497
1564
|
except Exception as e:
|
|
1498
1565
|
import traceback
|
|
@@ -1530,6 +1597,8 @@ def _register_routes(app: FastAPI):
|
|
|
1530
1597
|
bank_id=bank_id, search_query=q, limit=limit, offset=offset, request_context=request_context
|
|
1531
1598
|
)
|
|
1532
1599
|
return data
|
|
1600
|
+
except (AuthenticationError, HTTPException):
|
|
1601
|
+
raise
|
|
1533
1602
|
except Exception as e:
|
|
1534
1603
|
import traceback
|
|
1535
1604
|
|
|
@@ -1538,7 +1607,7 @@ def _register_routes(app: FastAPI):
|
|
|
1538
1607
|
raise HTTPException(status_code=500, detail=str(e))
|
|
1539
1608
|
|
|
1540
1609
|
@app.get(
|
|
1541
|
-
"/v1/default/banks/{bank_id}/documents/{document_id}",
|
|
1610
|
+
"/v1/default/banks/{bank_id}/documents/{document_id:path}",
|
|
1542
1611
|
response_model=DocumentResponse,
|
|
1543
1612
|
summary="Get document details",
|
|
1544
1613
|
description="Get a specific document including its original text",
|
|
@@ -1560,7 +1629,7 @@ def _register_routes(app: FastAPI):
|
|
|
1560
1629
|
if not document:
|
|
1561
1630
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
1562
1631
|
return document
|
|
1563
|
-
except HTTPException:
|
|
1632
|
+
except (AuthenticationError, HTTPException):
|
|
1564
1633
|
raise
|
|
1565
1634
|
except Exception as e:
|
|
1566
1635
|
import traceback
|
|
@@ -1570,7 +1639,7 @@ def _register_routes(app: FastAPI):
|
|
|
1570
1639
|
raise HTTPException(status_code=500, detail=str(e))
|
|
1571
1640
|
|
|
1572
1641
|
@app.get(
|
|
1573
|
-
"/v1/default/chunks/{chunk_id}",
|
|
1642
|
+
"/v1/default/chunks/{chunk_id:path}",
|
|
1574
1643
|
response_model=ChunkResponse,
|
|
1575
1644
|
summary="Get chunk details",
|
|
1576
1645
|
description="Get a specific chunk by its ID",
|
|
@@ -1589,7 +1658,7 @@ def _register_routes(app: FastAPI):
|
|
|
1589
1658
|
if not chunk:
|
|
1590
1659
|
raise HTTPException(status_code=404, detail="Chunk not found")
|
|
1591
1660
|
return chunk
|
|
1592
|
-
except HTTPException:
|
|
1661
|
+
except (AuthenticationError, HTTPException):
|
|
1593
1662
|
raise
|
|
1594
1663
|
except Exception as e:
|
|
1595
1664
|
import traceback
|
|
@@ -1599,7 +1668,7 @@ def _register_routes(app: FastAPI):
|
|
|
1599
1668
|
raise HTTPException(status_code=500, detail=str(e))
|
|
1600
1669
|
|
|
1601
1670
|
@app.delete(
|
|
1602
|
-
"/v1/default/banks/{bank_id}/documents/{document_id}",
|
|
1671
|
+
"/v1/default/banks/{bank_id}/documents/{document_id:path}",
|
|
1603
1672
|
response_model=DeleteDocumentResponse,
|
|
1604
1673
|
summary="Delete a document",
|
|
1605
1674
|
description="Delete a document and all its associated memory units and links.\n\n"
|
|
@@ -1633,7 +1702,7 @@ def _register_routes(app: FastAPI):
|
|
|
1633
1702
|
document_id=document_id,
|
|
1634
1703
|
memory_units_deleted=result["memory_units_deleted"],
|
|
1635
1704
|
)
|
|
1636
|
-
except HTTPException:
|
|
1705
|
+
except (AuthenticationError, HTTPException):
|
|
1637
1706
|
raise
|
|
1638
1707
|
except Exception as e:
|
|
1639
1708
|
import traceback
|
|
@@ -1658,6 +1727,8 @@ def _register_routes(app: FastAPI):
|
|
|
1658
1727
|
bank_id=bank_id,
|
|
1659
1728
|
operations=[OperationResponse(**op) for op in operations],
|
|
1660
1729
|
)
|
|
1730
|
+
except (AuthenticationError, HTTPException):
|
|
1731
|
+
raise
|
|
1661
1732
|
except Exception as e:
|
|
1662
1733
|
import traceback
|
|
1663
1734
|
|
|
@@ -1688,6 +1759,8 @@ def _register_routes(app: FastAPI):
|
|
|
1688
1759
|
return CancelOperationResponse(**result)
|
|
1689
1760
|
except ValueError as e:
|
|
1690
1761
|
raise HTTPException(status_code=404, detail=str(e))
|
|
1762
|
+
except (AuthenticationError, HTTPException):
|
|
1763
|
+
raise
|
|
1691
1764
|
except Exception as e:
|
|
1692
1765
|
import traceback
|
|
1693
1766
|
|
|
@@ -1719,6 +1792,8 @@ def _register_routes(app: FastAPI):
|
|
|
1719
1792
|
disposition=DispositionTraits(**disposition_dict),
|
|
1720
1793
|
background=profile["background"],
|
|
1721
1794
|
)
|
|
1795
|
+
except (AuthenticationError, HTTPException):
|
|
1796
|
+
raise
|
|
1722
1797
|
except Exception as e:
|
|
1723
1798
|
import traceback
|
|
1724
1799
|
|
|
@@ -1757,6 +1832,8 @@ def _register_routes(app: FastAPI):
|
|
|
1757
1832
|
disposition=DispositionTraits(**disposition_dict),
|
|
1758
1833
|
background=profile["background"],
|
|
1759
1834
|
)
|
|
1835
|
+
except (AuthenticationError, HTTPException):
|
|
1836
|
+
raise
|
|
1760
1837
|
except Exception as e:
|
|
1761
1838
|
import traceback
|
|
1762
1839
|
|
|
@@ -1786,6 +1863,8 @@ def _register_routes(app: FastAPI):
|
|
|
1786
1863
|
response.disposition = DispositionTraits(**result["disposition"])
|
|
1787
1864
|
|
|
1788
1865
|
return response
|
|
1866
|
+
except (AuthenticationError, HTTPException):
|
|
1867
|
+
raise
|
|
1789
1868
|
except Exception as e:
|
|
1790
1869
|
import traceback
|
|
1791
1870
|
|
|
@@ -1837,6 +1916,8 @@ def _register_routes(app: FastAPI):
|
|
|
1837
1916
|
disposition=DispositionTraits(**disposition_dict),
|
|
1838
1917
|
background=final_profile["background"],
|
|
1839
1918
|
)
|
|
1919
|
+
except (AuthenticationError, HTTPException):
|
|
1920
|
+
raise
|
|
1840
1921
|
except Exception as e:
|
|
1841
1922
|
import traceback
|
|
1842
1923
|
|
|
@@ -1864,6 +1945,8 @@ def _register_routes(app: FastAPI):
|
|
|
1864
1945
|
+ result.get("entities_deleted", 0)
|
|
1865
1946
|
+ result.get("documents_deleted", 0),
|
|
1866
1947
|
)
|
|
1948
|
+
except (AuthenticationError, HTTPException):
|
|
1949
|
+
raise
|
|
1867
1950
|
except Exception as e:
|
|
1868
1951
|
import traceback
|
|
1869
1952
|
|
|
@@ -1915,6 +1998,8 @@ def _register_routes(app: FastAPI):
|
|
|
1915
1998
|
content_dict["metadata"] = item.metadata
|
|
1916
1999
|
if item.document_id:
|
|
1917
2000
|
content_dict["document_id"] = item.document_id
|
|
2001
|
+
if item.entities:
|
|
2002
|
+
content_dict["entities"] = [{"text": e.text, "type": e.type or "CONCEPT"} for e in item.entities]
|
|
1918
2003
|
contents.append(content_dict)
|
|
1919
2004
|
|
|
1920
2005
|
if request.async_:
|
|
@@ -1938,6 +2023,10 @@ def _register_routes(app: FastAPI):
|
|
|
1938
2023
|
return RetainResponse.model_validate(
|
|
1939
2024
|
{"success": True, "bank_id": bank_id, "items_count": len(contents), "async": False}
|
|
1940
2025
|
)
|
|
2026
|
+
except OperationValidationError as e:
|
|
2027
|
+
raise HTTPException(status_code=e.status_code, detail=e.reason)
|
|
2028
|
+
except (AuthenticationError, HTTPException):
|
|
2029
|
+
raise
|
|
1941
2030
|
except Exception as e:
|
|
1942
2031
|
import traceback
|
|
1943
2032
|
|
|
@@ -1976,6 +2065,8 @@ def _register_routes(app: FastAPI):
|
|
|
1976
2065
|
await app.state.memory.delete_bank(bank_id, fact_type=type, request_context=request_context)
|
|
1977
2066
|
|
|
1978
2067
|
return DeleteResponse(success=True)
|
|
2068
|
+
except (AuthenticationError, HTTPException):
|
|
2069
|
+
raise
|
|
1979
2070
|
except Exception as e:
|
|
1980
2071
|
import traceback
|
|
1981
2072
|
|