Skip to content

Commit 64139cb

Browse files
Let an ontology field opt out, and fix the README
The Go DSL excludes a field with `zep:"-"`, so a model reused for other purposes can leave one out. Python raised on any field without a property marker with no way to opt out, so the same model could not be expressed here without splitting it. An `Excluded` marker, following the existing `Identity` pattern, skips the field before the marker check. The README still described capabilities this package does not ship: document collections, the langchain chat-history and vector-store classes, a community install of a differently named package, and an examples directory removed from the repository.
1 parent b41aae8 commit 64139cb

3 files changed

Lines changed: 60 additions & 60 deletions

File tree

‎README.md‎

Lines changed: 0 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -32,78 +32,18 @@ pip install zep-cloud
3232
> [!NOTE]
3333
> Zep Cloud [overview](https://help.getzep.com/concepts) and [cloud sdk guide](https://help.getzep.com/sdks).
3434
35-
### Community Installation
36-
```bash
37-
pip install zep-python
38-
```
39-
> [!NOTE]
40-
> Zep Community Edition [quick start](https://help.getzep.com/ce/quickstart) and [sdk guide](https://help.getzep.com/ce/sdks).
41-
42-
### Zep v0.x Compatible SDK
43-
You can install Zep v0.x compatible sdk by running:
44-
```bash
45-
pip install "zep-python>=1.5.0,<2.0.0"
46-
```
47-
> [!NOTE]
48-
> Zep v0.x [quick start](https://help.getzep.com/ce/legacy/deployment/quickstart) and [sdk guide](https://help.getzep.com/ce/legacy/sdk).
49-
5035
### How Zep works
5136

5237
Zep persists and recalls chat histories, and automatically generates summaries and other artifacts from these chat histories. It also embeds messages and summaries, enabling you to search Zep for relevant context from past conversations. Zep does all of this asynchronously, ensuring these operations don't impact your user's chat experience. Data is persisted to database, allowing you to scale out when growth demands.
5338

54-
Zep also provides a simple, easy to use abstraction for document vector search called Document Collections. This is designed to complement Zep's core context features, but is not designed to be a general purpose vector database.
55-
5639
Zep allows you to be more intentional about constructing your prompt:
5740
1. automatically adding a few recent messages, with the number customized for your app;
5841
2. a summary of recent conversations prior to the messages above;
5942
3. and/or contextually relevant summaries or messages surfaced from the entire chat session.
60-
4. and/or relevant Business data from Zep Document Collections.
61-
62-
Zep Cloud offers:
63-
- **Fact Extraction:** Automatically build fact tables from conversations, without having to define a data schema upfront.
64-
- **Dialog Classification:** Instantly and accurately classify chat dialog. Understand user intent and emotion, segment users, and more. Route chains based on semantic context, and trigger events.
65-
- **Structured Data Extraction:** Quickly extract business data from chat conversations using a schema you define. Understand what your Assistant should ask for next in order to complete its task.
6643

6744
You will also need to provide a Zep Project API key to your zep client.
6845
You can find out about zep projects in our [cloud docs](https://help.getzep.com/projects.html)
6946

70-
### Using LangChain Zep Classes with `zep-python`
71-
72-
(Currently only available on release candidate versions)
73-
74-
In the pre-release version `zep-python` sdk comes with `ZepChatMessageHistory` and `ZepVectorStore`
75-
classes that are compatible with [LangChain's Python expression language](https://python.langchain.com/docs/expression_language/)
76-
77-
In order to use these classes in your application, you need to make sure that you have
78-
`langchain_core` package installed, please refer to [Langchain's docs installation section](https://python.langchain.com/docs/get_started/installation#langchain-core).
79-
80-
We support `langchain_core@>=0.1.3<0.2.0`
81-
82-
You can import these classes in the following way:
83-
84-
```python
85-
from zep_cloud.langchain import ZepChatMessageHistory, ZepVectorStore
86-
```
87-
88-
### Running Examples
89-
You will need to set the following environment variables to run examples in the `examples` directory:
90-
91-
```dotenv
92-
# Please use examples/.env.example as a template for .env file
93-
94-
# Required
95-
ZEP_API_KEY=<zep-project-api-key># Your Zep Project API Key
96-
ZEP_COLLECTION=<zep-collection-name># used in ingestion script and in vector store examples
97-
OPENAI_API_KEY=<openai-api-key># Your OpenAI API Key
98-
99-
# Optional (If you want to use langsmith with LangServe Sample App)
100-
LANGCHAIN_TRACING_V2=true
101-
LANGCHAIN_API_KEY=<your-langchain-api-key>
102-
LANGCHAIN_PROJECT=<your-langchain-project-name># If not specified, defaults to "default"
103-
```
104-
105-
106-
10747
## Installation
10848

10949
```sh

‎src/zep_cloud/ontology.py‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ class TraveledTo(EdgeModel):
6262
"EntityFloat",
6363
"EntityBoolean",
6464
"Identity",
65+
"Excluded",
6566
"PropertyType",
6667
"build_ontology",
6768
]
@@ -88,6 +89,18 @@ class _Identity:
8889
Identity = _Identity()
8990

9091

92+
class _Excluded:
93+
"""Marks a field as left out of the ontology entirely."""
94+
95+
96+
# Annotate a field with this to leave it out of the ontology, regardless of
97+
# whether it also carries a property type marker. This is what lets a model
98+
# reused for other purposes, such as one already shaped by another schema,
99+
# keep a field that is not an ontology property instead of having to be split
100+
# into a separate class just for that field.
101+
Excluded = _Excluded()
102+
103+
91104
# The four property types the API accepts. Declared once: a change to the wire
92105
# spelling is a change here and nowhere else.
93106
EntityText = Annotated[typing.Optional[str], PropertyType("text")]
@@ -132,6 +145,8 @@ def _properties(
132145
properties: typing.List[EntityProperty] = []
133146
identity_properties: typing.List[str] = []
134147
for name, field in model.model_fields.items():
148+
if any(isinstance(m, _Excluded) for m in field.metadata):
149+
continue
135150
marker = next(
136151
(m for m in field.metadata if isinstance(m, PropertyType)),
137152
None,
@@ -161,6 +176,10 @@ def build_ontology(
161176
) -> typing.Tuple[typing.List[EntityType], typing.List[EdgeType]]:
162177
"""Derive the entity and edge type lists from the given model classes.
163178
179+
Every field needs a property type marker (``EntityText``, ``EntityInt``,
180+
``EntityFloat``, or ``EntityBoolean``), unless it is annotated with
181+
``Excluded``, which leaves it out of the ontology entirely.
182+
164183
Pass the result to ``graph.set_ontology`` for one graph, or to
165184
``project.set_ontology`` for the project default. v3 addressed many graphs in
166185
one call; v4 has one ontology endpoint per scope, so a caller targeting

‎tests/ontology/test_build_ontology.py‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
EntityInt,
1010
EntityModel,
1111
EntityText,
12+
Excluded,
1213
Identity,
1314
build_ontology,
1415
)
@@ -145,6 +146,46 @@ class Bad(EntityModel):
145146
build_ontology(entities={"Bad": Bad})
146147

147148

149+
def test_an_excluded_field_is_left_out_of_the_ontology():
150+
# A model reused for something other than the ontology can carry a field
151+
# that is not a property, the same way Go's `zep:"-"` struct tag lets a
152+
# struct field opt out.
153+
class Place(EntityModel):
154+
"""A place."""
155+
156+
country: EntityText = Field(default=None, description="Its country")
157+
internal_id: Annotated[str, Excluded] = "unused"
158+
159+
entity_types, _ = build_ontology(entities={"Place": Place})
160+
assert [p.name for p in entity_types[0].properties] == ["country"]
161+
162+
163+
def test_an_excluded_field_with_no_description_still_builds():
164+
# Excluded means the field is never read as a property at all, so it
165+
# cannot be rejected for missing a description either.
166+
class Place(EntityModel):
167+
"""A place."""
168+
169+
country: EntityText = Field(default=None, description="Its country")
170+
internal_id: Annotated[str, Excluded] = "unused"
171+
172+
entity_types, _ = build_ontology(entities={"Place": Place})
173+
assert len(entity_types[0].properties) == 1
174+
175+
176+
def test_an_unmarked_field_alongside_an_excluded_one_is_still_rejected():
177+
# Excluded opts a specific field out; it does not relax the requirement
178+
# for every other field to carry a property type marker.
179+
class Bad(EntityModel):
180+
"""Has one excluded field and one that is still unmarked."""
181+
182+
internal_id: Annotated[str, Excluded] = "unused"
183+
oops: str = "x"
184+
185+
with pytest.raises(ValueError, match="Bad.oops is not an ontology property"):
186+
build_ontology(entities={"Bad": Bad})
187+
188+
148189
def test_a_property_with_no_description_is_rejected_by_name():
149190
# The description goes into the extraction prompt; an empty one is accepted
150191
# by the write path and quietly degrades extraction.

0 commit comments

Comments
 (0)