Skip to content

Commit f3d8d8d

Browse files
jope-bmclaude[bot]phernandez
authored
fix: Use discriminated unions for MCP schema validation in build_context (#266)
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: Paul Hernandez <phernandez@users.noreply.github.com> Co-authored-by: jope-bm <jope-bm@users.noreply.github.com>
1 parent 9743fcd commit f3d8d8d

2 files changed

Lines changed: 15 additions & 11 deletions

File tree

src/basic_memory/schemas/memory.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
"""Schemas for memory context."""
22

33
from datetime import datetime
4-
from typing import List, Optional, Annotated, Sequence
4+
from typing import List, Optional, Annotated, Sequence, Literal, Union
55

66
from annotated_types import MinLen, MaxLen
77
from pydantic import BaseModel, Field, BeforeValidator, TypeAdapter
@@ -118,7 +118,7 @@ def memory_url_path(url: memory_url) -> str: # pyright: ignore
118118
class EntitySummary(BaseModel):
119119
"""Simplified entity representation."""
120120

121-
type: str = "entity"
121+
type: Literal["entity"] = "entity"
122122
permalink: Optional[str]
123123
title: str
124124
content: Optional[str] = None
@@ -129,7 +129,7 @@ class EntitySummary(BaseModel):
129129
class RelationSummary(BaseModel):
130130
"""Simplified relation representation."""
131131

132-
type: str = "relation"
132+
type: Literal["relation"] = "relation"
133133
title: str
134134
file_path: str
135135
permalink: str
@@ -142,7 +142,7 @@ class RelationSummary(BaseModel):
142142
class ObservationSummary(BaseModel):
143143
"""Simplified observation representation."""
144144

145-
type: str = "observation"
145+
type: Literal["observation"] = "observation"
146146
title: str
147147
file_path: str
148148
permalink: str
@@ -169,17 +169,21 @@ class MemoryMetadata(BaseModel):
169169
class ContextResult(BaseModel):
170170
"""Context result containing a primary item with its observations and related items."""
171171

172-
primary_result: EntitySummary | RelationSummary | ObservationSummary = Field(
173-
description="Primary item"
174-
)
172+
primary_result: Annotated[
173+
Union[EntitySummary, RelationSummary, ObservationSummary],
174+
Field(discriminator="type", description="Primary item")
175+
]
175176

176177
observations: Sequence[ObservationSummary] = Field(
177178
description="Observations belonging to this entity", default_factory=list
178179
)
179180

180-
related_results: Sequence[EntitySummary | RelationSummary | ObservationSummary] = Field(
181-
description="Related items", default_factory=list
182-
)
181+
related_results: Sequence[
182+
Annotated[
183+
Union[EntitySummary, RelationSummary, ObservationSummary],
184+
Field(discriminator="type")
185+
]
186+
] = Field(description="Related items", default_factory=list)
183187

184188

185189
class GraphContext(BaseModel):

tests/mcp/test_prompts.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ def test_prompt_context_with_file_path_no_permalink():
116116

117117
# Create a mock context with a file that has no permalink (like a binary file)
118118
test_entity = EntitySummary(
119-
type="file",
119+
type="entity",
120120
title="Test File",
121121
permalink=None, # No permalink
122122
file_path="test_file.pdf",

0 commit comments

Comments
 (0)