All notable changes to the zep-crewai package will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Added the
py.typedmarker so installedzep-crewaipackages expose their inline type annotations to PEP 561-compatible type checkers.
CrewAI 1.x removed its memory extension points (crewai.memory.storage.interface.Storage
and the ExternalMemory(storage=...) wrapper), so there is no automatic per-turn memory
loop to build -- the supported extension points remain tools, the standalone storage
adapters called from your app code, and kickoff-level seeding (re-check on future CrewAI
releases). Within that ceiling, this release brings zep-crewai up to the standardization
bar set by the other Zep framework integrations: out-of-band provisioning with lazy
fallback, a pluggable context builder, a configurable context template, a pin-or-expose
tool schema, payload truncation guards, and a save() that never raises into the crew.
This package is sync-only (CrewAI's adapters are built on the synchronous Zep client),
so all new APIs are synchronous and use the canonical names without a _sync suffix.
ensure_user/ensure_thread-- idempotent, out-of-band helpers (newzep_crewai.provisioningmodule) to provision the Zep user and thread before the first turn. Both return whether the resource was newly created, so callers can drive one-time per-user setup.ensure_useraccepts an optionalon_createdhook (UserSetupHook, sync:Callable[[Zep, str], None]) that fires only when the user is genuinely new; a genuine failure (auth, network, 5xx) or anon_createdhook error always propagates when called directly.ZepUserStorageandZepStoragenow lazily provision the Zep user and thread on firstsave()/search()(previously both had to exist before the first call, orsave()failed). The lazy path is hot-path-wrapped: a genuine failure or anon_createdhook error is logged and returnsFalse, never raised intosave()/search(). New constructor kwargsfirst_name,last_name,email, andon_createdfeed this path.ZepGraphStoragedeliberately has noon_created(it is scoped to a standalonegraph_id, not a Zep user -- there is no "user created" event to hook into) and now raisesTypeErrorif one is passed.context_builderconstructor kwarg onZepUserStorage(+ContextInput,ContextBuilderexports) -- an optional sync callable that entirely replaces the default thread-context + graph composition insearch(). Receives a single frozenContextInput(zep,user_id,thread_id,user_message); returns the context string orNonefor "no results". A builder exception is logged and degrades to empty results (the existingsearch()error contract). There is no concurrency here -- persistence (save) is a separate, caller-driven call in CrewAI's model, so nothing is gathered against the builder.context_templateconstructor kwarg onZepUserStorageandZepGraphStorage(and acontext_templateparameter onsearch_graph_and_compose_context) -- configures the template wrapping the composed/built context returned fromsearch()(default:DEFAULT_CONTEXT_TEMPLATE, an explicit<ZEP_CONTEXT>...</ZEP_CONTEXT>block, canonical across zep-adk's Python, Go, and TypeScript implementations). Rendered via plain string replacement (str.replace("{context}", ...)), neverstr.format, so context text containing{,}, or%is always safe to inject.ZepSearchTool/create_search_toolgain pin-or-expose control:scope(all six ofedges,nodes,episodes,observations,thread_summaries,auto),reranker(rrf,mmr,node_distance,episode_mentions,cross_encoder),limit,mmr_lambda, andcenter_node_uuidare now all model-exposed by default. Newpinned_params/hidden_paramskeyword arguments fix a parameter to a constant (hidden from the model) or hide it without pinning (Zep's own default applies).search_filtersandbfs_origin_node_uuidsare new constructor-only keyword arguments (never exposed to the model).- New
zep_crewai.limitsmodule:truncate_message_contentguards thesave()-to-thread.add_messagespaths (ZepStorage,ZepUserStorage) against Zep's 4,096-char message limit (truncates to 4,000, logging lengths only, never content);truncate_graph_dataguards thegraph.addpaths (ZepGraphStorage.save,ZepAddDataTool, and the storage adapters' graph save paths) against Zep's payload ceiling (truncates to 9,900 chars, matching the ag2/autogen precedent).
- Breaking:
ZepSearchTool/create_search_tool's tool schema changed (pin-or-expose). Previously the model sawquery,limit, and a freeformscopestring with four documented values (edges,nodes,episodes,all); everything else was hardcoded. Now theargs_schemais built dynamically withpydantic.create_modeland exposesscope(six typed values -- the compoundallscope is removed; pin or let the model choose a scope, or useautoto let Zep decide),reranker,limit,mmr_lambda, andcenter_node_uuid. Newscope=/reranker=/limit=constructor arguments pin (and hide) the corresponding parameter for fixed configuration. A parameter neither pinned nor supplied by the model (e.g.mmr_lambdaleft unset) is omitted from thegraph.searchcall entirely, never forwarded as an explicitNone. Result formatting changed from the numbered[FACT]/[ENTITY]list to the compact- factline format shared by the sibling integrations, and a Zep failure returns an error string rather than raising. - Breaking (behavioral):
save()no longer raises on Zep errors. PreviouslyZepStorage.save(),ZepUserStorage.save(), andZepGraphStorage.save()logged the error and re-raised it into the crew, crashing the run on a Zep outage. All three now log the error and return normally -- persistence failures degrade gracefully instead of propagating. Callers that relied on catching those exceptions should useensure_user/ensure_threadout-of-band for loud provisioning failures and monitor logs for persistence errors. search()results fromZepUserStorage/ZepGraphStorageare now wrapped incontext_template(previously the rawcompose_context_stringoutput was returned). Callers that parsed the raw composition should read the block inside<ZEP_CONTEXT>...</ZEP_CONTEXT>or passcontext_template="{context}"to restore the old shape.
Pinning search parameters:
# Before (1.1.x) -- the model saw query/limit/scope, everything else was hardcoded
tool = create_search_tool(zep_client, user_id="user-1")
# After (1.2.0) -- all search params are model-exposed by default; pin what the
# model should not control:
tool = create_search_tool(
zep_client, user_id="user-1", pinned_params={"scope": "nodes", "limit": 5}
)
# or hide a param without pinning it (Zep's own default applies):
tool = create_search_tool(zep_client, user_id="user-1", hidden_params={"reranker"})Provisioning a user before the first turn (optional -- the storage adapters now also provision lazily, but out-of-band provisioning fails loudly and is recommended):
from zep_crewai import ensure_user, ensure_thread
ensure_user(zep_client, user_id="user-1", first_name="Jane", email="jane@example.com")
ensure_thread(zep_client, thread_id="thread-1", user_id="user-1")
storage = ZepUserStorage(client=zep_client, user_id="user-1", thread_id="thread-1")- Modernized for the latest dependencies: CrewAI 1.x and
zep-cloud>=3.23.0. ZepStorage,ZepUserStorage, andZepGraphStorageare now standalone, framework-agnostic Zep storage adapters. CrewAI 1.x removedcrewai.memory.storage.interface.Storage(and theExternalMemory(storage=...)wrapper /external_memory=Crew kwarg that consumed it), so these classes no longer subclass a CrewAI base. Their publicsave(value, metadata)/search(query, limit, score_threshold)/reset()API and Zep behavior (messages →thread.add_messages, data →graph.add, search →thread.get_user_context+graph.search) are preserved.- Dependency-check import in
__init__.pyswitched from the removedcrewai.memory.storage.interfacetocrewai.tools(the supported extension point used byZepSearchTool/ZepAddDataTool). - Updated examples and README to wire Zep into CrewAI agents via the
ZepSearchTool/ZepAddDataToolinstead of the removedExternalMemory.
- Dropped the
modeargument fromthread.get_user_contextcalls. Zep V3 removed the thread contextmode("summary"/"basic") option and auto-assembles the Context Block.
ZepUserStorage(mode=...)is now accepted for backward compatibility but ignored, and emits aDeprecationWarning.
zep-cloudlower bound raised to>=3.23.0.crewailower bound raised to>=1.0.0.