@@ -125,7 +125,8 @@ class EntitySummary(BaseModel):
125125
126126 type : Literal ["entity" ] = "entity"
127127 external_id : str # UUID for v2 API routing
128- entity_id : Optional [int ] = Field (None , exclude = True ) # Internal DB ID
128+ # COMPAT(v0.18): old clients expect these fields in JSON
129+ entity_id : Optional [int ] = None
129130 permalink : Optional [str ]
130131 title : str
131132 content : Optional [str ] = None
@@ -143,18 +144,19 @@ class RelationSummary(BaseModel):
143144 """Simplified relation representation."""
144145
145146 type : Literal ["relation" ] = "relation"
146- relation_id : Optional [int ] = Field (None , exclude = True ) # Internal DB ID
147- entity_id : Optional [int ] = Field (None , exclude = True ) # Internal FK
147+ # COMPAT(v0.18): old clients expect these fields in JSON
148+ relation_id : Optional [int ] = None
149+ entity_id : Optional [int ] = None
148150 title : str
149151 file_path : str
150152 permalink : str
151153 relation_type : str
152154 from_entity : Optional [str ] = None
153- from_entity_id : Optional [int ] = Field ( None , exclude = True ) # Internal FK
154- from_entity_external_id : Optional [str ] = Field ( None , exclude = True ) # Internal routing ID
155+ from_entity_id : Optional [int ] = None
156+ from_entity_external_id : Optional [str ] = None
155157 to_entity : Optional [str ] = None
156- to_entity_id : Optional [int ] = Field ( None , exclude = True ) # Internal FK
157- to_entity_external_id : Optional [str ] = Field ( None , exclude = True ) # Internal routing ID
158+ to_entity_id : Optional [int ] = None
159+ to_entity_external_id : Optional [str ] = None
158160 created_at : Annotated [
159161 datetime , Field (json_schema_extra = {"type" : "string" , "format" : "date-time" })
160162 ]
@@ -168,10 +170,11 @@ class ObservationSummary(BaseModel):
168170 """Simplified observation representation."""
169171
170172 type : Literal ["observation" ] = "observation"
171- observation_id : Optional [int ] = Field (None , exclude = True ) # Internal DB ID
172- entity_id : Optional [int ] = Field (None , exclude = True ) # Internal FK
173- entity_external_id : Optional [str ] = Field (None , exclude = True ) # Internal routing ID
174- title : Optional [str ] = Field (None , exclude = True ) # Redundant with parent entity
173+ # COMPAT(v0.18): old clients expect these fields in JSON
174+ observation_id : Optional [int ] = None
175+ entity_id : Optional [int ] = None
176+ entity_external_id : Optional [str ] = None
177+ title : Optional [str ] = None
175178 file_path : str
176179 permalink : str
177180 category : str
@@ -192,13 +195,18 @@ class MemoryMetadata(BaseModel):
192195 types : Optional [List [SearchItemType ]] = None
193196 depth : int
194197 timeframe : Optional [str ] = None
195- generated_at : Optional [datetime ] = Field (None , exclude = True ) # Internal timing
196- primary_count : Optional [int ] = None # Changed field name
197- related_count : Optional [int ] = None # Changed field name
198- total_results : Optional [int ] = Field (None , exclude = True ) # Internal counter
198+ # COMPAT(v0.18): old clients expect generated_at and total_results in JSON
199+ generated_at : Optional [datetime ] = None
200+ primary_count : Optional [int ] = None
201+ related_count : Optional [int ] = None
202+ total_results : Optional [int ] = None
199203 total_relations : Optional [int ] = None
200204 total_observations : Optional [int ] = None
201205
206+ @field_serializer ("generated_at" )
207+ def serialize_generated_at (self , dt : Optional [datetime ]) -> Optional [str ]:
208+ return dt .isoformat () if dt else None
209+
202210
203211class ContextResult (BaseModel ):
204212 """Context result containing a primary item with its observations and related items."""
0 commit comments