# Welcome to Zep!


  Connect your AI coding assistant to Zep's docs: [MCP server & llms.txt](/coding-with-llms)


Zep is a context engineering platform that systematically assembles personalized context—user preferences, traits, and business data—for reliable agent applications. Zep combines agent memory, Graph RAG, and context assembly capabilities to deliver comprehensive personalized context that reduces hallucinations and improves accuracy.


  
    Learn about Zep's context engineering platform, temporal knowledge graphs, and agent memory capabilities.
  

  
    Get up and running with Zep in minutes, whether you code in Python, TypeScript, or Go.
  

  
    Discover practical recipes and patterns for common use cases with Zep.
  

  
    Comprehensive API documentation for Zep's SDKs in Python, TypeScript, and Go.
  

  
    Migrate from Mem0 to Zep in minutes.
  

  
    Learn about Graphiti, Zep's open-source temporal knowledge graph framework.
  



# Coding with LLMs

> Integrate Zep's documentation directly into your AI coding workflow using llms.txt and MCP.

Zep provides tools that give AI coding assistants direct access to Zep's documentation: a real-time MCP server and standardized llms.txt files for enhanced code generation and troubleshooting.

## MCP Server

Zep's Model Context Protocol (MCP) server gives AI assistants real-time access to search Zep's complete documentation.

**Server details:**

* URL: `docs-mcp.getzep.com`
* Type: Search-based with SSE transport
* Capabilities: Real-time documentation search and retrieval

### Setting up the MCP server


  
    Add the SSE server using the CLI:

    ```bash
    claude mcp add --transport sse zep-docs docs-mcp.getzep.com
    ```
  

  
    Create `.cursor/mcp.json` in your project or `~/.cursor/mcp.json` globally:

    ```json
    {
      "mcpServers": {
        "zep-docs": {
          "transport": "sse",
          "url": "docs-mcp.getzep.com"
        }
      }
    }
    ```

    Enable MCP servers in Cursor settings, then add and enable the zep-docs server.
  

  
    Configure your MCP client with SSE transport:

    ```
    Transport: sse
    URL: docs-mcp.getzep.com
    ```

    
      Requires SSE support. Claude Desktop and non-SSE clients are incompatible.
    
  


### Using the MCP server

Once configured, AI assistants can automatically:

* Search Zep concepts and features
* Find code examples and tutorials
* Access current API documentation
* Retrieve troubleshooting information

## llms.txt

Zep publishes standardized `llms.txt` files containing essential information for AI coding assistants:

* Core concepts and architecture
* Usage patterns and examples
* API reference summaries
* Best practices and troubleshooting
* Framework integration examples

### Accessing llms.txt

Zep provides two versions of the llms.txt file:

**Standard version** (recommended for most use cases):

```
https://help.getzep.com/llms.txt
```

**Comprehensive version** (for advanced use cases):

```
https://help.getzep.com/llms-full.txt
```

The standard version contains curated essentials, while the comprehensive version includes complete documentation but is much larger. Most AI assistants work better with the standard version due to context limitations.


# Key Concepts

> Understanding Zep's context engineering platform and temporal knowledge graphs.


  Looking to just get coding? Check out our [Quickstart](/quickstart).


## Summary

| Concept                       | Description                                                                                                                                                                                                      | Docs                                                  |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------- |
| Knowledge Graph               | Zep's memory store for agents. Nodes represent entities, edges represent facts/relationships. The graph updates dynamically in response to new data.                                                             | [Docs](/understanding-the-graph)                      |
| Memory Context String         | Optimized string containing facts and entities from the knowledge graph most relevant to the current session. Also contains dates when facts became valid and invalid. Provide this to your chatbot as "memory". | [Docs](/concepts#memory-context)                      |
| Fact Invalidation             | When new data invalidates a prior fact, the time the fact became invalid is stored on that fact's edge in the knowledge graph.                                                                                   | [Docs](/facts)                                        |
| JSON/text/message             | Types of data that can be ingested into the knowledge graph. Can represent business data, documents, chat messages, emails, etc.                                                                                 | [Docs](/adding-data-to-the-graph#adding-message-data) |
| Custom entity types           | Feature allowing use of Pydantic-like classes to customize creation/retrieval of entities in the knowledge graph.                                                                                                | [Docs](/entity-types)                                 |
| User                          | Create a user in Zep to represent an individual using your application. Each user has their own knowledge graph.                                                                                                 | [Docs](/users)                                        |
| Sessions                      | Conversation threads of a user. By default, all messages added to any session of that user are ingested into that user's knowledge graph.                                                                        | [Docs](/sessions)                                     |
| Group                         | Used for creating an arbitrary knowledge graph that is not necessarily tied to a user. Useful for memory shared by a "group" of users.                                                                           | [Docs](/groups)                                       |
| `memory.add` & `graph.add`    | High level and low level methods for adding data to the knowledge graph.                                                                                                                                         | [Docs](/concepts#using-memoryadd)                     |
| `memory.get` & `graph.search` | High level and low level methods for retrieving from the knowledge graph.                                                                                                                                        | [Docs](/concepts#using-memoryget)                     |
| Fact Ratings                  | Feature for rating and filtering facts by relevance to your use case.                                                                                                                                            | [Docs](/facts#rating-facts-for-relevancy)             |

Zep is a context engineering platform that systematically assembles personalized context—user preferences, traits, and business data—for reliable agent applications. Zep combines agent memory, Graph RAG, and context assembly capabilities to deliver comprehensive personalized context that reduces hallucinations and improves accuracy.

## What is Context Engineering?

Context Engineering is the discipline of assembling all necessary information, instructions, and tools around a LLM to help it accomplish tasks reliably. Unlike simple prompt engineering, context engineering involves building dynamic systems that provide the right information in the right format so LLMs can perform consistently.

The core challenge: LLMs are stateless and only know what's in their immediate context window. Context engineering bridges this gap by systematically providing relevant background knowledge, user history, business data, and tool outputs.

Using [user chat histories and business data](#business-data-vs-chat-message-data), Zep automatically constructs a [temporal knowledge graph](#the-knowledge-graph) for each of your users. The knowledge graph contains entities, relationships, and facts related to your user. As facts change or are superseded, [Zep updates the graph](#managing-changes-in-facts-over-time) to reflect their new state. Through systematic context engineering, Zep provides your agent with the comprehensive information needed to deliver personalized responses and solve problems. This reduces hallucinations, improves accuracy, and reduces the cost of LLM calls.



This guide covers key concepts for using Zep effectively:

* [How Zep fits into your application](#how-zep-fits-into-your-application)
* [The Zep Knowledge Graph](#the-knowledge-graph)
* [User vs Group graphs](#user-vs-group-graphs)
* [Managing changes in facts over time](#managing-changes-in-facts-over-time)
* [Business data vs Chat Message data](#business-data-vs-chat-message-data)
* [Users and Chat Sessions](#users-and-chat-sessions)
* [Adding Memory](#adding-memory)
* [Retrieving memory](#retrieving-memory)
* [Improving Fact Quality](#improving-fact-quality)
* [Using Zep as an agentic tool](#using-zep-as-an-agentic-tool)

## How Zep fits into your application

Your application sends Zep messages and other interactions your agent has with a human. Zep can also ingest data from your business sources in JSON, text, or chat message format. These sources may include CRM applications, emails, billing data, or conversations on other communication platforms like Slack.


  


Zep automatically fuses this data together on a temporal knowledge graph, building a holistic view of the user's world and the relationships between entities. Zep offers a number of APIs for [adding and retrieving memory](#retrieving-memory). In addition to populating a prompt with Zep's engineered context, Zep's search APIs can be used to build [agentic tools](#using-zep-as-an-agentic-tool).

The example below shows Zep's `memory.context` field resulting from a call to `memory.get()`. This is Zep's engineered context string that can be added to your prompt and contains facts and graph entities relevant to the current conversation with a user. For more about the temporal context of facts, see [Managing changes in facts over time](#managing-changes-in-facts-over-time).

Zep also returns a number of other artifacts in the `memory.get()` response, including raw `facts` objects. Zep's search methods can also be used to retrieve nodes, edges, and facts.

### Memory Context

Memory context is Zep's engineered context string containing relevant facts and entities for the session. It is always present in the result of `memory.get()`
call and can be optionally [received with the response of `memory.add()` call](/docs/performance/performance-best-practices#get-the-memory-context-string-sooner).


  ```python Python
  # pass in the session ID of the conversation thread
  memory = zep_client.memory.get(session_id="session_id") 
  print(memory.context)
  ```


```text
FACTS and ENTITIES represent relevant context to the current conversation.

# These are the most relevant facts and their valid date ranges

# format: FACT (Date range: from - to)


  - Emily is experiencing issues with logging in. (2024-11-14 02:13:19+00:00 -
    present) 
  - User account Emily0e62 has a suspended status due to payment failure. 
    (2024-11-14 02:03:58+00:00 - present) 
  - user has the id of Emily0e62 (2024-11-14 02:03:54 - present)
  - The failed transaction used a card with last four digits 1234. (2024-09-15
    00:00:00+00:00 - present)
  - The reason for the transaction failure was 'Card expired'. (2024-09-15
    00:00:00+00:00 - present)
  - user has the name of Emily Painter (2024-11-14 02:03:54 - present) 
  - Account Emily0e62 made a failed transaction of 99.99. (2024-07-30 
    00:00:00+00:00 - 2024-08-30 00:00:00+00:00)


# These are the most relevant entities

# ENTITY_NAME: entity summary


  - Emily0e62: Emily0e62 is a user account associated with a transaction,
    currently suspended due to payment failure, and is also experiencing issues
    with logging in. 
  - Card expired: The node represents the reason for the transaction failure, 
    which is indicated as 'Card expired'. 
  - Magic Pen Tool: The tool being used by the user that is malfunctioning. 
  - User: user 
  - Support Agent: Support agent responding to the user's bug report. 
  - SupportBot: SupportBot is the virtual assistant providing support to the user, 
    Emily, identified as SupportBot. 
  - Emily Painter: Emily is a user reporting a bug with the magic pen tool, 
    similar to Emily Painter, who is expressing frustration with the AI art
    generation tool and seeking assistance regarding issues with the PaintWiz app.

```

You can then include this context in your system prompt:

| MessageType | Content                                                 |
| ----------- | ------------------------------------------------------- |
| `System`    | Your system prompt 

`{Zep context string}` | | `Assistant` | An assistant message stored in Zep | | `User` | A user message stored in Zep | | ... | ... | | `User` | The latest user message | ## The Knowledge Graph A knowledge graph is a network of interconnected facts, such as *"Kendra loves Adidas shoes."* Each fact is a *"triplet"* represented by two entities, or nodes (*"Kendra", "Adidas shoes"*), and their relationship, or edge (*"loves"*).
Knowledge Graphs have been explored extensively for information retrieval. What makes Zep unique is its ability to autonomously build temporal knowledge graphs while handling changing relationships and maintaining historical context.
Zep automatically constructs a temporal knowledge graph for each of your users. The knowledge graph contains entities, relationships, and facts related to your user, while automatically handling changing relationships and facts over time. Here's an example of how Zep might extract graph data from a chat message, and then update the graph once new information is available: ![graphiti intro slides](file:34e08b39-3f7d-4aab-b4f8-9389d1300d4e) Each node and edge contains certain attributes - notably, a fact is always stored as an edge attribute. There are also datetime attributes for when the fact becomes [valid and when it becomes invalid](#managing-changes-in-facts-over-time). ## User vs Group graphs Zep automatically creates a knowledge graph for each User of your application. You as the developer can also create a ["group graph"](/groups) (which is best thought of as an "arbitrary graph") for memory to be used by a group of Users, or for a more complicated use case. For example, you could create a group graph for your company's product information or even messages related to a group chat. This avoids having to add the same data to each user graph. To do so, you'd use the `graph.add()` and `graph.search()` methods (see [Retrieving memory](#retrieving-memory)). Group knowledge is not retrieved via the `memory.get()` method and is not included in the `memory.context` string. To use user and group graphs simultaneously, you need to add group-specific context to your prompt alongside the `memory.context` string. Read more about groups [here](/groups). ## Managing changes in facts over time When incorporating new data, Zep looks for existing nodes and edges in graph and decides whether to add new nodes/edges or to update existing ones. An update could mean updating an edge (for example, indicating the previous fact is no longer valid). For example, in the [animation above](#the-knowledge-graph), Kendra initially loves Adidas shoes. She later is angry that the shoes broke and states a preference for Puma shoes. As a result, Zep invalidates the fact that Kendra loves Adidas shoes and creates two new facts: "Kendra's Adidas shoes broke" and "Kendra likes Puma shoes". Zep also looks for dates in all ingested data, such as the timestamp on a chat message or an article's publication date, informing how Zep sets the following edge attributes. This assists your agent in reasoning with time. | Edge attribute | Example | | :-------------- | :---------------------------------------------- | | **created\_at** | The time Zep learned that the user got married | | **valid\_at** | The time the user got married | | **invalid\_at** | The time the user got divorced | | **expired\_at** | The time Zep learned that the user got divorced | The `valid_at` and `invalid_at` attributes for each fact are then included in the `memory.context` string which is given to your agent: ```text # format: FACT (Date range: from - to) User account Emily0e62 has a suspended status due to payment failure. (2024-11-14 02:03:58+00:00 - present) ``` ## Business data vs Chat Message data Zep can ingest either unstructured text (e.g. documents, articles, chat messages) or JSON data (e.g. business data, or any other form of structured data). Conversational data is ingested through `memory.add()` in structured chat message format, and all other data is ingested through the `graph.add()` method. ## Users and Chat Sessions A Session is a series of chat messages (e.g., between a user and your agent). [Users](/users) may have multiple Sessions. Entities, relationships, and facts are extracted from the messages in a Session and added to the user's knowledge graph. All of a user's Sessions contribute to a single, shared knowledge graph for that user. Read more about sessions [here](/sessions). `SessionIDs` are arbitrary identifiers that you can map to relevant business objects in your app, such as users or a conversation a user might have with your app. For code examples of how to create users and sessions, see the [Quickstart Guide](/quickstart#create-a-user-and-session). ## Adding Memory There are two ways to add data to Zep: `memory.add()` and `graph.add()`. ### Using `memory.add()` Add your chat history to Zep using the `memory.add()` method. `memory.add` is session-specific and expects data in chat message format, including a `role` name (e.g., user's real name), `role_type` (AI, human, tool), and message `content`. Zep stores the chat history and builds a user-level knowledge graph from the messages. For code examples of how to add messages to Zep's memory, see the [Quickstart Guide](/quickstart#adding-messages-and-retrieving-context). For best results, add chat history to Zep on every chat turn. That is, add both the AI and human messages in a single operation and in the order that the messages were created. Additionally, for latency-sensitive applications, you can request the memory context directly in the response to the `memory.add` call. Read more [here](/docs/performance/performance-best-practices#get-the-memory-context-string-sooner). ### Using `graph.add()` The `graph.add()` method enables you to add business data as a JSON object or unstructured text. It also supports adding data to Group graphs by passing in a `group_id` as opposed to a `user_id`. For code examples of how to add business data to the graph, see the [Quickstart Guide](/quickstart#adding-business-data-to-a-graph). ## Retrieving memory There are three ways to retrieve memory from Zep: `memory.get()`, `graph.search()`, and methods for retrieving specific nodes, edges, or episodes using UUIDs. ### Using `memory.get()` The `memory.get()` method is a user-friendly, high-level API for retrieving relevant context from Zep. It uses the latest messages of the *given session* to determine what information is most relevant from the user's knowledge graph and returns that information in a [context string](#memory-context) for your prompt. Note that although `memory.get()` only requires a session ID, it is able to return memory derived from any session of that user. The session is just used to determine what's relevant. `memory.get` also returns recent chat messages and raw facts that may provide additional context for your agent. It is user and session-specific and cannot retrieve data from group graphs. For code examples of how to retrieve memory context for a session, see the [Quickstart Guide](/quickstart#retrieving-context-with-memoryget). ### Using `graph.search()` The `graph.search()` method lets you search the graph directly, returning raw edges and/or nodes (defaults to edges), as opposed to facts. You can customize search parameters, such as the reranker used. For more on how search works, visit the [Graph Search](/searching-the-graph) guide. This method works for both User and Group graphs. For code examples of how to search the graph, see the [Quickstart Guide](/quickstart#searching-the-graph). ### Retrieving specific nodes, edges, and episodes Zep offers several utility methods for retrieving specific nodes, edges, or episodes by UUID, or all elements for a user or group. To retrieve a fact, you just need to retrieve its edge, since a fact is always the attribute of some edge. See the [Graph SDK reference](/sdk-reference/graph) for more. ## Improving Fact Quality By using Zep's fact rating feature, you can make Zep automatically assign a rating to every fact using your own custom rating instruction. Then, when retrieving memory, you can set a minimum rating threshold so that the memory only contains the highest quality facts for your use case. Read more [here](/facts#rating-facts-for-relevancy). ## Using Zep as an agentic tool Zep's memory retrieval methods can be used as agentic tools, enabling your agent to query Zep for relevant information. This allows your agent to access the user's knowledge graph and retrieve facts, entities, and relationships that are relevant to the current conversation. For a complete code example of how to use Zep as an agentic tool, see the [Quickstart Guide](/quickstart#using-zep-as-an-agentic-tool). # Quickstart > Get up and running with Zep in minutes Looking for a more in-depth understanding? Check out our [Key Concepts](/concepts) page. This quickstart guide will help you get up and running with Zep quickly. We will: * Obtain an API key * Install the SDK * Initialize the client * Create a user and session * Add and retrieve messages * View your knowledge graph * Add business data to a user or group graph * Search for edges or nodes in the graph Migrating from Mem0? Check out our [Mem0 Migration](/mem0-to-zep) guide. ## Obtain an API Key [Create a free Zep account](https://app.getzep.com/) and you will be prompted to create an API key. ## Install the SDK ### Python Set up your Python project, ideally with [a virtual environment](https://medium.com/@vkmauryavk/managing-python-virtual-environments-with-uv-a-comprehensive-guide-ac74d3ad8dff), and then: ```Bash pip install zep-cloud ``` ```Bash uv pip install zep-cloud ``` ### TypeScript Set up your TypeScript project and then: ```Bash npm install @getzep/zep-cloud ``` ```Bash yarn add @getzep/zep-cloud ``` ```Bash pnpm install @getzep/zep-cloud ``` ### Go Set up your Go project and then: ```Bash go get github.com/getzep/zep-go/v2 ``` ## Initialize the Client First, make sure you have a [.env file](https://metaschool.so/articles/what-are-env-files) with your API key: ``` ZEP_API_KEY=your_api_key_here ``` After creating your .env file, you'll need to source it in your terminal session: ```bash source .env ``` Then, initialize the client with your API key: ```python Python import os from zep_cloud.client import Zep API_KEY = os.environ.get('ZEP_API_KEY') client = Zep( api_key=API_KEY, ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const API_KEY = process.env.ZEP_API_KEY; const client = new ZepClient({ apiKey: API_KEY, }); ``` ```go Go import ( "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" "log" ) client := zepclient.NewClient( option.WithAPIKey(os.Getenv("ZEP_API_KEY")), ) ``` **The Python SDK Supports Async Use** The Python SDK supports both synchronous and asynchronous usage. For async operations, import `AsyncZep` instead of `Zep` and remember to `await` client calls in your async code. ## Create a User and Session Before adding messages, you need to create a user and a session. A session is a chat thread - a container for messages between a user and an assistant. A user can have multiple sessions (different conversation threads). While messages are stored in sessions, the knowledge extracted from these messages is stored at the user level. This means that facts and entities learned in one session are available across all of the user's sessions. When you use `memory.get()`, Zep returns the most relevant memory from the user's entire knowledge graph, not just from the current session. ### Create a User It is important to provide at least the first name and ideally the last name of the user when calling `user.add`. Otherwise, Zep may not be able to correctly associate the user with references to the user in the data you add. If you don't have this information at the time the user is created, you can add it later with our [update user](/sdk-reference/user/update) method. ```python Python # Create a new user user_id = "user123" new_user = client.user.add( user_id=user_id, email="[email protected]", first_name="Jane", last_name="Smith", ) ``` ```typescript TypeScript // Create a new user const userId = "user123"; const user = await client.user.add({ userId: userId, email: "[email protected]", firstName: "Jane", lastName: "Smith", }); ``` ```go Go import ( "context" v2 "github.com/getzep/zep-go/v2" ) // Create a new user userId := "user123" email := "[email protected]" firstName := "Jane" lastName := "Smith" user, err := client.User.Add(context.TODO(), &v2.CreateUserRequest{ UserID: &userId, Email: &email, FirstName: &firstName, LastName: &lastName, }) if err != nil { log.Fatal("Error creating user:", err) } fmt.Println("User created:", user) ``` ### Create a Session ```python Python import uuid # Generate a unique session ID session_id = uuid.uuid4().hex # Create a new session for the user client.memory.add_session( session_id=session_id, user_id=user_id, ) ``` ```typescript TypeScript import { v4 as uuid } from "uuid"; // Generate a unique session ID const sessionId = uuid(); // Create a new session for the user await client.memory.addSession({ sessionId: sessionId, userId: userId, }); ``` ```go Go import ( "context" "github.com/google/uuid" "github.com/getzep/zep-go/v2/models" ) // Generate a unique session ID sessionId := uuid.New().String() // Create a new session for the user session, err := client.Memory.AddSession(context.TODO(), &v2.CreateSessionRequest{ SessionID: sessionId, UserID: userId, }) if err != nil { log.Fatal("Error creating session:", err) } fmt.Println("Session created:", session) ``` ## Add Messages with memory.add Add chat messages to a session using the `memory.add` method. These messages will be stored in the session history and used to build the user's knowledge graph. It is important to provide the name of the user in the role field if possible, to help with graph construction. It's also helpful to provide a meaningful name for the assistant in its role field. ```python Python # Define messages to add from zep_cloud.types import Message messages = [ Message( role="Jane", content="Hi, my name is Jane Smith and I work at Acme Corp.", role_type="user", ), Message( role="AI Assistant", content="Hello Jane! Nice to meet you. How can I help you with Acme Corp today?", role_type="assistant", ) ] # Add messages to the session client.memory.add(session_id, messages=messages) ``` ```typescript TypeScript // Define messages to add import type { Message } from "@getzep/zep-cloud/api"; const messages: Message[] = [ { role: "Jane", content: "Hi, my name is Jane Smith and I work at Acme Corp.", roleType: "user", }, { role: "AI Assistant", content: "Hello Jane! Nice to meet you. How can I help you with Acme Corp today?", roleType: "assistant", } ]; // Add messages to the session await client.memory.add(sessionId, { messages }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2/models" ) // Define messages to add userRole := "Jane" assistantRole := "AI Assistant" messages := []*v2.Message{ { Role: &userRole, Content: "Hi, my name is Jane Smith and I work at Acme Corp.", RoleType: "user", }, { Role: &assistantRole, Content: "Hello Jane! Nice to meet you. How can I help you with Acme Corp today?", RoleType: "assistant", }, } // Add messages to the session _, err = client.Memory.Add( context.TODO(), sessionId, &v2.AddMemoryRequest{ Messages: messages, }, ) if err != nil { log.Fatal("Error adding messages:", err) } ``` ## Retrieve Context with memory.get Use the `memory.get` method to retrieve relevant context for a session. This includes a context string with facts and entities and recent messages that can be used in your prompt. ```python Python # Get memory for the session memory = client.memory.get(session_id=session_id) # Access the context string (for use in prompts) context_string = memory.context print(context_string) # Access recent messages recent_messages = memory.messages for msg in recent_messages: print(f"{msg.role}: {msg.content}") ``` ```typescript TypeScript // Get memory for the session const memory = await client.memory.get(sessionId); // Access the context string (for use in prompts) const contextString = memory.context; console.log(contextString); // Access recent messages if (memory.messages) { memory.messages.forEach(msg => { console.log(`${msg.role}: ${msg.content}`); }); } ``` ```go Go import ( "context" "fmt" ) // Get memory for the session memory, err := client.Memory.Get(context.TODO(), sessionId, nil) if err != nil { log.Fatal("Error getting memory:", err) } // Access the context string (for use in prompts) contextString := memory.Context fmt.Println(contextString) // Access recent messages recentMessages := memory.Messages for _, msg := range recentMessages { fmt.Printf("%s: %s\n", *msg.Role, msg.Content) } ``` ## View your Knowledge Graph Since you've created memory, you can view your knowledge graph by navigating to [the Zep Dashboard](https://app.getzep.com/), then Users > "user123" > View Graph. You can also click the "View Episodes" button to see when data is finished being added to the knowledge graph. ## Add Business Data to a Graph You can add business data directly to a user's graph or to a group graph using the `graph.add` method. This data can be in the form of messages, text, or JSON. ```python Python # Add text data to a user's graph new_episode = client.graph.add( user_id=user_id, type="text", data="Jane Smith is a senior software engineer who has been with Acme Corp for 5 years." ) print("New episode created:", new_episode) # Add JSON data to a user's graph import json json_data = { "employee": { "name": "Jane Smith", "position": "Senior Software Engineer", "department": "Engineering", "projects": ["Project Alpha", "Project Beta"] } } client.graph.add( user_id=user_id, type="json", data=json.dumps(json_data) ) # Add data to a group graph (shared across users) group_id = "engineering_team" client.graph.add( group_id=group_id, type="text", data="The engineering team is working on Project Alpha and Project Beta." ) ``` ```typescript TypeScript // Add text data to a user's graph const newEpisode = await client.graph.add({ userId: userId, type: "text", data: "Jane Smith is a senior software engineer who has been with Acme Corp for 5 years." }); console.log("New episode created:", newEpisode); // Add JSON data to a user's graph const jsonData = { employee: { name: "Jane Smith", position: "Senior Software Engineer", department: "Engineering", projects: ["Project Alpha", "Project Beta"] } }; await client.graph.add({ userId: userId, type: "json", data: JSON.stringify(jsonData) }); // Add data to a group graph (shared across users) const groupId = "engineering_team"; await client.graph.add({ groupId: groupId, type: "text", data: "The engineering team is working on Project Alpha and Project Beta." }); ``` ```go Go import ( "context" "encoding/json" "github.com/getzep/zep-go/v2/models" ) // Add text data to a user's graph data := "Jane Smith is a senior software engineer who has been with Acme Corp for 5 years." newEpisode, err := client.Graph.Add(context.TODO(), &v2.AddDataRequest{ UserID: &userId, Type: v2.GraphDataTypeText.Ptr(), Data: &data, }) if err != nil { log.Fatal("Error adding text data:", err) } fmt.Println("New episode added:", newEpisode) // Add JSON data to a user's graph type Employee struct { Name string `json:"name"` Position string `json:"position"` Department string `json:"department"` Projects []string `json:"projects"` } jsonData := map[string]Employee{ "employee": { Name: "Jane Smith", Position: "Senior Software Engineer", Department: "Engineering", Projects: []string{"Project Alpha", "Project Beta"}, }, } jsonBytes, err := json.Marshal(jsonData) if err != nil { log.Fatal("Error marshaling JSON data:", err) } jsonString := string(jsonBytes) _, err = client.Graph.Add(context.TODO(), &v2.AddDataRequest{ UserID: &userId, Type: v2.GraphDataTypeJSON.Ptr(), Data: &jsonString, }) if err != nil { log.Fatal("Error adding JSON data:", err) } // Add data to a group graph (shared across users) groupId := "engineering_team" groupData := "The engineering team is working on Project Alpha and Project Beta." _, err = client.Graph.Add(context.TODO(), &v2.AddDataRequest{ GroupID: &groupId, Type: v2.GraphDataTypeText.Ptr(), Data: &groupData, }) if err != nil { log.Fatal("Error adding group data:", err) } ``` ## Search the Graph Use the `graph.search` method to search for edges or nodes in the graph. This is useful for finding specific information about a user or group. ```python Python # Search for edges in a user's graph edge_results = client.graph.search( user_id=user_id, query="What projects is Jane working on?", scope="edges", # Default is "edges" limit=5 ) # Search for nodes in a user's graph node_results = client.graph.search( user_id=user_id, query="Jane Smith", scope="nodes", limit=5 ) # Search in a group graph group_results = client.graph.search( group_id=group_id, query="Project Alpha", scope="edges", limit=5 ) ``` ```typescript TypeScript // Search for edges in a user's graph const edgeResults = await client.graph.search({ userId: userId, query: "What projects is Jane working on?", scope: "edges", // Default is "edges" limit: 5 }); // Search for nodes in a user's graph const nodeResults = await client.graph.search({ userId: userId, query: "Jane Smith", scope: "nodes", limit: 5 }); // Search in a group graph const groupResults = await client.graph.search({ groupId: groupId, query: "Project Alpha", scope: "edges", limit: 5 }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2/models" ) // Search for edges in a user's graph limit := 5 edgeResults, err := client.Graph.Search(context.TODO(), &v2.GraphSearchQuery{ UserID: &userId, Query: "What projects is Jane working on?", Scope: v2.GraphSearchScopeEdges.Ptr(), Limit: &limit, }) if err != nil { log.Fatal("Error searching graph:", err) } fmt.Println("Edge search results:", edgeResults) // Search for nodes in a user's graph nodeResults, err := client.Graph.Search(context.TODO(), &v2.GraphSearchQuery{ UserID: &userId, Query: "Jane Smith", Scope: v2.GraphSearchScopeNodes.Ptr(), Limit: &limit, }) if err != nil { log.Fatal("Error searching graph:", err) } fmt.Println("Node search results:", nodeResults) // Search in a group graph groupResults, err := client.Graph.Search(context.TODO(), &v2.GraphSearchQuery{ GroupID: &groupId, Query: "Project Alpha", Scope: v2.GraphSearchScopeEdges.Ptr(), Limit: &limit, }) if err != nil { log.Fatal("Error searching graph:", err) } fmt.Println("Group search results:", groupResults) ``` ## Use Zep as an Agentic Tool Zep's memory retrieval methods can be used as agentic tools, enabling your agent to query Zep for relevant information. The example below shows how to create a LangChain LangGraph tool to search for facts in a user's graph. ```python Python from zep_cloud.client import AsyncZep from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, MessagesState from langgraph.prebuilt import ToolNode zep = AsyncZep(api_key=os.environ.get('ZEP_API_KEY')) @tool async def search_facts(state: MessagesState, query: str, limit: int = 5): """Search for facts in all conversations had with a user. Args: state (MessagesState): The Agent's state. query (str): The search query. limit (int): The number of results to return. Defaults to 5. Returns: list: A list of facts that match the search query. """ search_results = await zep.graph.search( user_id=state['user_name'], query=query, limit=limit, ) return [edge.fact for edge in search_results.edges] tools = [search_facts] tool_node = ToolNode(tools) llm = ChatOpenAI(model='gpt-4o-mini', temperature=0).bind_tools(tools) ``` ## Next Steps Now that you've learned the basics of using Zep, you can: * Learn more about [Key Concepts](/concepts) * Explore the [Graph API](/adding-data-to-the-graph) for adding and retrieving data * Understand [Users and Sessions](/users) in more detail * Learn about [Memory Context](/concepts#memory-context) for building better prompts * Explore [Graph Search](/searching-the-graph) for advanced search capabilities # Building a Chatbot with Zep > Familiarize yourself with Zep and the Zep SDKs, culminating in building a simple chatbot. For an introduction to Zep's memory layer, Knowledge Graph, and other key concepts, see the [Concepts Guide](/concepts). A Jupyter notebook version of this guide is [available here](https://github.com/getzep/zep-python/blob/main/examples/quickstart/quickstart.ipynb). In this guide, we'll walk through a simple example of how to use Zep Cloud to build a chatbot. We're going to upload a number of datasets to Zep, building a graph of data about a user. Then we'll use the Zep Python SDK to retrieve and search the data. Finally, we'll build a simple chatbot that uses Zep to retrieve and search data to respond to a user. ## Set up your environment 1. Sign up for a [Zep Cloud](https://www.getzep.com/) account. 2. Ensure you install required dependencies into your Python environment before running this notebook. See [Installing Zep SDKs](sdks.mdx) for more information. Optionally create your environment in a `virtualenv`. ```bash pip install zep-cloud openai rich python-dotenv ``` 3. Ensure that you have a `.env` file in your working directory that includes your `ZEP_API_KEY` and `OPENAI_API_KEY`: Zep API keys are specific to a project. You can create multiple keys for a single project. Visit `Project Settings` in the Zep dashboard to manage your API keys. ```text ZEP_API_KEY= OPENAI_API_KEY= ``` ```python Python import os import json import uuid from openai import OpenAI import rich from dotenv import load_dotenv from zep_cloud.client import Zep from zep_cloud import Message load_dotenv() zep = Zep(api_key=os.environ.get("ZEP_API_KEY")) oai_client = OpenAI( api_key=os.getenv("OPENAI_API_KEY"), ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; import * as dotenv from "dotenv"; import { v4 as uuidv4 } from 'uuid'; import OpenAI from 'openai'; dotenv.config(); const zep = new ZepClient({ apiKey: process.env.ZEP_API_KEY }); const oai_client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, }); ``` We also provide an [Asynchronous Python client](/sdks#initialize-client) . ## Create User and add a Session Users in Zep may have one or more chat sessions. These are threads of messages between the user and an agent. Include the user's **full name** and **email address** when creating a user. This improves Zep's ability to associate data, such as emails or documents, with a user. ```python Python bot_name = "SupportBot" user_name = "Emily" user_id = user_name + str(uuid.uuid4())[:4] session_id = str(uuid.uuid4()) zep.user.add( user_id=user_id, email=f"{user_name}@painters.com", first_name=user_name, last_name="Painter", ) zep.memory.add_session( user_id=user_id, session_id=session_id, ) ``` ```typescript TypeScript const bot_name = "SupportBot"; const user_name = "Emily"; const user_id = user_name + uuidv4().substring(0, 4); const session_id = uuidv4(); await zep.user.add({ userId: user_id, email: `${user_name}@painters.com`, firstName: user_name, lastName: "Painter", }); await zep.memory.addSession({ userId: user_id, sessionId: session_id, }); ``` ## Datasets We're going to use the [memory](/concepts#using-memoryadd) and [graph](/adding-data-to-the-graph) APIs to upload an assortment of data to Zep. These include past dialog with the agent, CRM support cases, and billing data. ```python Python support_cases = [ { "subject": "Bug: Magic Pen Tool Drawing Goats Instead of Boats", "messages": [ { "role": "user", "content": "Whenever I use the magic pen tool to draw boats, it ends up drawing goats instead.", "timestamp": "2024-03-16T14:20:00Z", }, { "role": "support_agent", "content": f"Hi {user_name}, that sounds like a bug! Thanks for reporting it. Could you let me know exactly how you're using the tool when this happens?", "timestamp": "2024-03-16T14:22:00Z", }, { "role": "user", "content": "Sure, I select the magic pen, draw a boat shape, and it just replaces the shape with goats.", "timestamp": "2024-03-16T14:25:00Z", }, { "role": "support_agent", "content": "Got it! We'll escalate this to our engineering team. In the meantime, you can manually select the boat shape from the options rather than drawing it with the pen.", "timestamp": "2024-03-16T14:27:00Z", }, { "role": "user", "content": "Okay, thanks. I hope it gets fixed soon!", "timestamp": "2024-03-16T14:30:00Z", }, ], "status": "escalated", }, ] chat_history = [ { "role": "assistant", "name": bot_name, "content": f"Hello {user_name}, welcome to PaintWiz support. How can I assist you today?", "timestamp": "2024-03-15T10:00:00Z", }, { "role": "user", "name": user_name, "content": "I'm absolutely furious! Your AI art generation is completely broken!", "timestamp": "2024-03-15T10:02:00Z", }, { "role": "assistant", "name": bot_name, "content": f"I'm sorry to hear that you're experiencing issues, {user_name}. Can you please provide more details about what's going wrong?", "timestamp": "2024-03-15T10:03:00Z", }, { "role": "user", "name": user_name, "content": "Every time I try to draw mountains, your stupid app keeps turning them into fountains! And what's worse, all the people in my drawings have six fingers! It's ridiculous!", "timestamp": "2024-03-15T10:05:00Z", }, { "role": "assistant", "name": bot_name, "content": f"I sincerely apologize for the frustration this is causing you, {user_name}. That certainly sounds like a significant glitch in our system. I understand how disruptive this can be to your artistic process. Can you tell me which specific tool or feature you're using when this occurs?", "timestamp": "2024-03-15T10:06:00Z", }, { "role": "user", "name": user_name, "content": "I'm using the landscape generator and the character creator. Both are completely messed up. How could you let this happen?", "timestamp": "2024-03-15T10:08:00Z", }, ] transactions = [ { "date": "2024-07-30", "amount": 99.99, "status": "Success", "account_id": user_id, "card_last_four": "1234", }, { "date": "2024-08-30", "amount": 99.99, "status": "Failed", "account_id": user_id, "card_last_four": "1234", "failure_reason": "Card expired", }, { "date": "2024-09-15", "amount": 99.99, "status": "Failed", "account_id": user_id, "card_last_four": "1234", "failure_reason": "Card expired", }, ] account_status = { "user_id": user_id, "account": { "account_id": user_id, "account_status": { "status": "suspended", "reason": "payment failure", }, }, } def convert_to_zep_messages(chat_history: list[dict[str, str | None]]) -> list[Message]: """ Convert chat history to Zep messages. Args: chat_history (list): List of dictionaries containing chat messages. Returns: list: List of Zep Message objects. """ return [ Message( role_type=msg["role"], role=msg.get("name", None), content=msg["content"], ) for msg in chat_history ] # Zep's high-level API allows us to add a list of messages to a session. zep.memory.add( session_id=session_id, messages=convert_to_zep_messages(chat_history) ) # The lower-level data API allows us to add arbitrary data to a user's Knowledge Graph. for tx in transactions: zep.graph.add(user_id=user_id, data=json.dumps(tx), type="json") zep.graph.add( user_id=user_id, data=json.dumps(account_status), type="json" ) for case in support_cases: zep.graph.add(user_id=user_id, data=json.dumps(case), type="json") ``` ```typescript TypeScript const support_cases = [ { subject: "Bug: Magic Pen Tool Drawing Goats Instead of Boats", messages: [ { role: "user", content: "Whenever I use the magic pen tool to draw boats, it ends up drawing goats instead.", timestamp: "2024-03-16T14:20:00Z", }, { role: "support_agent", content: `Hi ${user_name}, that sounds like a bug! Thanks for reporting it. Could you let me know exactly how you're using the tool when this happens?`, timestamp: "2024-03-16T14:22:00Z", }, { role: "user", content: "Sure, I select the magic pen, draw a boat shape, and it just replaces the shape with goats.", timestamp: "2024-03-16T14:25:00Z", }, { role: "support_agent", content: "Got it! We'll escalate this to our engineering team. In the meantime, you can manually select the boat shape from the options rather than drawing it with the pen.", timestamp: "2024-03-16T14:27:00Z", }, { role: "user", content: "Okay, thanks. I hope it gets fixed soon!", timestamp: "2024-03-16T14:30:00Z", }, ], status: "escalated", }, ]; const chat_history = [ { role: "assistant", name: bot_name, content: `Hello ${user_name}, welcome to PaintWiz support. How can I assist you today?`, timestamp: "2024-03-15T10:00:00Z", }, { role: "user", name: user_name, content: "I'm absolutely furious! Your AI art generation is completely broken!", timestamp: "2024-03-15T10:02:00Z", }, { role: "assistant", name: bot_name, content: `I'm sorry to hear that you're experiencing issues, ${user_name}. Can you please provide more details about what's going wrong?`, timestamp: "2024-03-15T10:03:00Z", }, { role: "user", name: user_name, content: "Every time I try to draw mountains, your stupid app keeps turning them into fountains! And what's worse, all the people in my drawings have six fingers! It's ridiculous!", timestamp: "2024-03-15T10:05:00Z", }, { role: "assistant", name: bot_name, content: `I sincerely apologize for the frustration this is causing you, ${user_name}. That certainly sounds like a significant glitch in our system. I understand how disruptive this can be to your artistic process. Can you tell me which specific tool or feature you're using when this occurs?`, timestamp: "2024-03-15T10:06:00Z", }, { role: "user", name: user_name, content: "I'm using the landscape generator and the character creator. Both are completely messed up. How could you let this happen?", timestamp: "2024-03-15T10:08:00Z", }, ]; const transactions = [ { date: "2024-07-30", amount: 99.99, status: "Success", account_id: user_id, card_last_four: "1234", }, { date: "2024-08-30", amount: 99.99, status: "Failed", account_id: user_id, card_last_four: "1234", failure_reason: "Card expired", }, { date: "2024-09-15", amount: 99.99, status: "Failed", account_id: user_id, card_last_four: "1234", failure_reason: "Card expired", }, ]; const account_status = { user_id: user_id, account: { account_id: user_id, account_status: { status: "suspended", reason: "payment failure", }, }, }; /** * Convert chat history to Zep messages. * * Args: * chatHistory (array): Array of objects containing chat messages. * * Returns: * array: Array of Zep message objects. */ const convertToZepMessages = (chatHistory: any[]) => { return chatHistory.map(msg => ({ roleType: msg.role, role: msg.name || null, content: msg.content, })); }; // Zep's high-level API allows us to add a list of messages to a session. await zep.memory.add(session_id, { messages: convertToZepMessages(chat_history) }); // The lower-level data API allows us to add arbitrary data to a user's Knowledge Graph. for (const tx of transactions) { await zep.graph.add({ userId: user_id, type: "json", data: JSON.stringify(tx) }); await zep.graph.add({ userId: user_id, type: "json", data: JSON.stringify(account_status) }); } for (const case_data of support_cases) { await zep.graph.add({ userId: user_id, type: "json", data: JSON.stringify(case_data) }); } ``` ### Wait a minute or two! We've batch uploaded a number of datasets that need to be ingested into Zep's graph before they can be queried. In ordinary operation, this data would stream into Zep and ingestion latency would be negligible. ## Retrieve data from Zep We'll start with getting a list of facts, which are stored on the edges of the graph. We'll see the temporal data associated with facts as well as the graph nodes the fact is related to. This data is also viewable in the Zep Web application. ```python Python all_user_edges = zep.graph.edge.get_by_user_id(user_id=user_id) rich.print(all_user_edges[:3]) ``` ```typescript TypeScript const all_user_edges = await zep.graph.edge.getByUserId(user_id); console.log(all_user_edges.slice(0, 3)); ``` ```text [ EntityEdge( created_at='2025-02-20T20:31:01.769332Z', episodes=['0d3a35c7-ebd3-427d-89a6-1a8dabd2df64'], expired_at='2025-02-20T20:31:18.742184Z', fact='The transaction failed because the card expired.', invalid_at='2024-09-15T00:00:00Z', name='HAS_FAILURE_REASON', source_node_uuid='06c61c00-9101-474f-9bca-42b4308ec378', target_node_uuid='07efd834-f07a-4c3c-9b32-d2fd9362afd5', uuid_='fb5ee0df-3aa0-44f3-889d-5bb163971b07', valid_at='2024-08-30T00:00:00Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ), EntityEdge( created_at='2025-02-20T20:31:33.771557Z', episodes=['60d1d20e-ed6c-4966-b1da-3f4ca274a524'], expired_at=None, fact='Emily uses the magic pen tool to draw boats.', invalid_at=None, name='USES_TOOL', source_node_uuid='36f5c5c6-eb16-4ebb-9db0-fd34809482f5', target_node_uuid='e337522d-3a62-4c45-975d-904e1ba25667', uuid_='f9eb0a98-1624-4932-86ca-be75a3c248e5', valid_at='2025-02-20T20:29:40.217412Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ), EntityEdge( created_at='2025-02-20T20:30:28.499178Z', episodes=['b8e4da4c-dd5e-4c48-bdbc-9e6568cd2d2e'], expired_at=None, fact="SupportBot understands how disruptive the glitch in the AI art generation can be to Emily's artistic process.", invalid_at=None, name='UNDERSTANDS', source_node_uuid='fd4ab1f0-e19e-40b7-aaec-78bd97571725', target_node_uuid='8e5686fc-f175-4da9-8778-ad8d60fc469a', uuid_='f8c52a21-e938-46a3-b930-04671d0c018a', valid_at='2025-02-20T20:29:39.08846Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ) ] ``` The high-level [memory API](/concepts#using-memoryget) provides an easy way to retrieve memory relevant to the current conversation by using the last 4 messages and their proximity to the User node. The `memory.get` method is a good starting point for retrieving relevant conversation context. It shortcuts passing recent messages to the `graph.search` API and returns a [context string](/concepts#memory-context), raw facts, and historical chat messages, providing everything needed for your agent's prompts. ```python Python memory = zep.memory.get(session_id=session_id) rich.print(memory.context) ``` ```typescript TypeScript const memory = await zep.memory.get(session_id); console.log(memory.context); ``` ```text FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) - SupportBot understands how disruptive the glitch in the AI art generation can be to Emily's artistic process. (2025-02-20 20:29:39 - present) - SupportBot sincerely apologizes to Emily for the frustration caused by the issues with the AI art generation. (2025-02-20 20:29:39 - present) - Emily has contacted SupportBot for assistance regarding issues she is experiencing. (2025-02-20 20:29:39 - present) - The user Emily reported a bug regarding the magic pen tool drawing goats instead of boats. (2024-03-16 14:20:00 - present) - The bug report has been escalated to the engineering team. (2024-03-16 14:27:00 - present) - Emily is a user of the AI art generation. (2025-02-20 20:29:39 - present) - user has the name of Emily Painter (2025-02-20 20:29:39 - present) - Emily5e57 is using the landscape generator. (2025-02-20 20:29:39 - 2025-02-20 20:29:39) - user has the id of Emily5e57 (2025-02-20 20:29:39 - present) - user has the email of [email protected] (2025-02-20 20:29:39 - present) - Emily is furious about the stupid app. (2025-02-20 20:29:39 - present) - Emily claims that the AI art generation is completely broken. (2025-02-20 20:29:39 - present) # These are the most relevant entities # ENTITY_NAME: entity summary - Emily Painter: Emily Painter contacted PaintWiz support for assistance, where she was welcomed by the support bot that inquired about the specific issues she was facing to provide better help. - [email protected]: user with the email of [email protected] - Emily5e57: Emily5e57, a user of the PaintWiz AI art generation tool, successfully processed a transaction of $99.99 on July 30, 2024, using a card ending in '1234'. However, she is experiencing significant frustration with the application due to malfunctions, such as the landscape generator incorrectly transforming mountains into fountains and characters being depicted with six fingers. These issues have led her to question the reliability of the tool, and she considers it to be completely broken. Emily has reached out to PaintWiz support for assistance, as these problems are severely disrupting her artistic process. - PaintWiz support: PaintWiz is an AI art generation platform that provides tools for users to create art. Recently, a user named Emily reported significant issues with the service, claiming that the AI art generation is not functioning properly. The support bot responded to her concerns, apologizing for the disruption to her artistic process and asking for more details about the specific tool or feature she was using. This interaction highlights PaintWiz's commitment to customer support, as they actively seek to assist users with their inquiries and problems related to their products. - SupportBot: A support agent named Emily addressed a user's report about a bug in a drawing application where the magic pen tool incorrectly produced goats instead of boats. After confirming the issue, she escalated it to the engineering team and suggested a temporary workaround of manually selecting the boat shape. Meanwhile, SupportBot, a virtual assistant for PaintWiz, also assisted another user named Emily who was frustrated with the AI art generation feature, acknowledging her concerns and requesting more details to help resolve the problem. - AI art generation: Emily, a user, expressed her frustration regarding the AI art generation, stating that it is completely broken. - options: The user reported a bug with the magic pen tool, stating that when attempting to draw boats, the tool instead draws goats. The support agent acknowledged the issue and requested more details about how the user was utilizing the tool. The user explained that they select the magic pen and draw a boat shape, but it gets replaced with goats. The support agent confirmed they would escalate the issue to the engineering team and suggested that the user manually select the boat shape from the options instead of drawing it with the pen. The user expressed hope for a quick resolution. ``` ```python Python rich.print(memory.messages) ``` ```typescript TypeScript console.log(memory.messages); ``` ```text [ Message( content='Hello Emily, welcome to PaintWiz support. How can I assist you today?', created_at='2025-02-20T20:29:39.08846Z', metadata=None, role='SupportBot', role_type='assistant', token_count=0, updated_at='0001-01-01T00:00:00Z', uuid_='e2b86f93-84d6-4270-adbc-e421f39b6f90' ), Message( content="I'm absolutely furious! Your AI art generation is completely broken!", created_at='2025-02-20T20:29:39.08846Z', metadata=None, role='Emily', role_type='user', token_count=0, updated_at='0001-01-01T00:00:00Z', uuid_='ec39e501-6dcc-4f8c-b300-f586d66005d8' ) ] ``` We can also use the [graph API](/searching-the-graph) to search edges/facts for arbitrary text. This API offers more options, including the ability to search node summaries and various re-rankers. ```python Python r = zep.graph.search(user_id=user_id, query="Why are there so many goats?", limit=4, scope="edges") rich.print(r.edges) ``` ```typescript TypeScript const r = await zep.graph.search({ userId: user_id, query: "Why are there so many goats?", limit: 4, scope: "edges" }); console.log(r.edges); ``` ```text [ EntityEdge( created_at='2025-02-20T20:31:33.771566Z', episodes=['60d1d20e-ed6c-4966-b1da-3f4ca274a524'], expired_at=None, fact='The magic pen tool draws goats instead of boats when used by Emily.', invalid_at=None, name='DRAWS_INSTEAD_OF', source_node_uuid='e337522d-3a62-4c45-975d-904e1ba25667', target_node_uuid='9814a57f-53a4-4d4a-ad5a-15331858ce18', uuid_='022687b6-ae08-4fef-9d6e-17afb07acdea', valid_at='2025-02-20T20:29:40.217412Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ), EntityEdge( created_at='2025-02-20T20:31:33.771528Z', episodes=['60d1d20e-ed6c-4966-b1da-3f4ca274a524'], expired_at=None, fact='The user Emily reported a bug regarding the magic pen tool drawing goats instead of boats.', invalid_at=None, name='REPORTED_BY', source_node_uuid='36f5c5c6-eb16-4ebb-9db0-fd34809482f5', target_node_uuid='cff4e758-d1a4-4910-abe7-20101a1f0d77', uuid_='5c3124ec-b4a3-4564-a38f-02338e3db4c4', valid_at='2024-03-16T14:20:00Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ), EntityEdge( created_at='2025-02-20T20:30:19.910797Z', episodes=['ff9eba8b-9e90-4765-a0ce-15eb44410f70'], expired_at=None, fact='The stupid app generates mountains.', invalid_at=None, name='GENERATES', source_node_uuid='b6e5a0ee-8823-4647-b536-5e6af0ba113a', target_node_uuid='43aaf7c9-628c-4bf0-b7cb-02d3e9c1a49c', uuid_='3514a3ad-1ed5-42c7-9f70-02834e8904bf', valid_at='2025-02-20T20:29:39.08846Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ), EntityEdge( created_at='2025-02-20T20:30:19.910816Z', episodes=['ff9eba8b-9e90-4765-a0ce-15eb44410f70'], expired_at=None, fact='The stupid app keeps turning mountains into fountains.', invalid_at=None, name='TRANSFORMS_INTO', source_node_uuid='43aaf7c9-628c-4bf0-b7cb-02d3e9c1a49c', target_node_uuid='0c90b42c-2b9f-4998-aa67-cc968f9002d3', uuid_='2f113810-3597-47a4-93c5-96d8002366fa', valid_at='2025-02-20T20:29:39.08846Z', graph_id='8e5686fc-f175-4da9-8778-ad8d60fc469a' ) ] ``` ## Creating a simple Chatbot In the next cells, Emily starts a new chat session with a support agent and complains that she can't log in. Our simple chatbot will, given relevant facts retrieved from Zep's graph, respond accordingly. Here, the support agent is provided with Emily's billing information and account status, which Zep retrieves as most relevant to Emily's login issue. ```python Python new_session_id = str(uuid.uuid4()) emily_message = "Hi, I can't log in!" # We start a new session indicating that Emily has started a new chat with the support agent. zep.memory.add_session(user_id=user_id, session_id=new_session_id) # We need to add the Emily's message to the session in order for memory.get to return # relevant facts related to the message zep.memory.add( session_id=new_session_id, messages=[Message(role_type="user", role=user_name, content=emily_message)], ) ``` ```typescript TypeScript const new_session_id = uuidv4(); const emily_message = "Hi, I can't log in!"; // We start a new session indicating that Emily has started a new chat with the support agent. await zep.memory.addSession({ userId: user_id, sessionId: new_session_id }); // We need to add the Emily's message to the session in order for memory.get to return // relevant facts related to the message await zep.memory.add(new_session_id, { messages: [{ roleType: "user", role: user_name, content: emily_message }] }); ``` ```python Python system_message = """ You are a customer support agent. Carefully review the facts about the user below and respond to the user's question. Be helpful and friendly. """ memory = zep.memory.get(session_id=new_session_id) messages = [ { "role": "system", "content": system_message, }, { "role": "assistant", # The context field is an opinionated string that contains facts and entities relevant to the current conversation. "content": memory.context, }, { "role": "user", "content": emily_message, }, ] response = oai_client.chat.completions.create( model="gpt-4o-mini", messages=messages, temperature=0, ) print(response.choices[0].message.content) ``` ```typescript TypeScript const system_message = ` You are a customer support agent. Carefully review the facts about the user below and respond to the user's question. Be helpful and friendly. `; const new_memory = await zep.memory.get(new_session_id); const messages = [ { role: "system" as const, content: system_message, }, { role: "assistant" as const, // The context field is an opinionated string that contains facts and entities relevant to the current conversation. content: new_memory.context || "", }, { role: "user" as const, content: emily_message, }, ]; const response = await oai_client.chat.completions.create({ model: "gpt-4o-mini", messages: messages, temperature: 0, }); console.log(response.choices[0].message.content); ``` ```text Hi Emily! I'm here to help you. It looks like your account is currently suspended due to a payment failure. This might be the reason you're unable to log in. The last transaction on your account failed because the card you were using has expired. If you update your payment information, we can help you get your account reactivated. Would you like assistance with that? ``` Let's look at the memory context string Zep retrieved for the above `memory.get` call. ```python Python rich.print(memory.context) ``` ```typescript TypeScript console.log(new_memory.context); ``` ```text FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) - Account with ID 'Emily1c2e' has a status of 'suspended'. (2025-02-24 23:24:29 - present) - user has the id of Emily1c2e (2025-02-24 23:24:29 - present) - User with ID 'Emily1c2e' has an account with ID 'Emily1c2e'. (2025-02-24 23:24:29 - present) - The bug report has been escalated to the engineering team. (2024-03-16 14:27:00 - present) - user has the name of Emily Painter (2025-02-24 23:24:29 - present) - Emily is the person being assisted by SupportBot. (2025-02-24 23:24:28 - present) - Emily1c2e is using the character creator. (2025-02-24 23:24:28 - present) - The reason for the account status 'suspended' is 'payment failure'. (2025-02-24 23:24:29 - present) - SupportBot is part of PaintWiz support. (2025-02-24 23:24:28 - present) - user has the email of [email protected] (2025-02-24 23:24:29 - present) - Emily is a user of PaintWiz. (2025-02-24 23:24:28 - present) - The support agent suggested that Emily manually select the boat shape from the options. (2025-02-24 23:24:29 - present) - All the people in Emily1c2e's drawings have six fingers. (2025-02-24 23:24:28 - present) - Emily1c2e is using the landscape generator. (2025-02-24 23:24:28 - present) - Emily is a user of the AI art generation. (2025-02-24 23:24:28 - present) - Emily states that the AI art generation is completely broken. (2025-02-24 23:24:28 - present) - The magic pen tool draws goats instead of boats when used by Emily. (2025-02-24 23:24:29 - present) - Emily1c2e tries to draw mountains. (2025-02-24 23:24:28 - present) # These are the most relevant entities # ENTITY_NAME: entity summary - goats: In a recent support interaction, a user reported a bug with the magic pen tool in a drawing application, where attempting to draw boats resulted in the tool drawing goats instead. The user, Emily, described the issue, stating that whenever she selects the magic pen and draws a boat shape, it is replaced with a goat shape. The support agent acknowledged the problem and confirmed it would be escalated to the engineering team for resolution. In the meantime, the agent suggested that Emily could manually select the boat shape from the available options instead of using the pen tool. Emily expressed her hope for a quick fix to the issue. - failure_reason: Two transactions failed due to expired cards: one on September 15, 2024, and another on August 30, 2024, for the amount of $99.99 associated with account ID 'Emily1c2e'. - status: User account "Emily1c2e" is suspended due to a payment failure. A transaction of $99.99 on September 15, 2024, failed because the card ending in "1234" had expired. This card had previously been used successfully for the same amount on July 30, 2024, but a failure on August 30, 2024, resulted in the account's suspension. - bug: A user reported a bug with the magic pen tool, stating that when attempting to draw boats, the tool instead draws goats. The support agent acknowledged the issue and requested more details about how the user was utilizing the tool. The user explained that they select the magic pen and draw a boat shape, but it gets replaced with goats. The support agent confirmed the bug and stated that it would be escalated to the engineering team for resolution. In the meantime, they suggested that the user manually select the boat shape from the options instead of using the pen. The user expressed hope for a quick fix. - user_id: Emily reported a bug with the magic pen tool in a drawing application, where attempting to draw boats resulted in goats being drawn instead. A support agent acknowledged the issue and requested more details. Emily explained her process, and the agent confirmed the bug, stating it would be escalated to the engineering team. As a temporary workaround, the agent suggested manually selecting the boat shape. Emily expressed hope for a quick resolution. Additionally, it was noted that another user, identified as "Emily1c2e," has a suspended account due to a payment failure. - people: Emily is frustrated with the AI art generation feature of PaintWiz, specifically mentioning that the people in her drawings are depicted with six fingers, which she finds ridiculous. - character creator: Emily is experiencing significant issues with the character creator feature of the app. She reports that when using the landscape generator and character creator, the app is malfunctioning, resulting in bizarre outcomes such as people in her drawings having six fingers. Emily expresses her frustration, stating that the AI art generation is completely broken and is not functioning as expected. ``` # Memory > Learn how to use the Memory API to store and retrieve memory. Zep's agent memory capabilities make context engineering simple: you add memory with a single line, retrieve memory with a single line, and then can immediately use the retrieved memory in your next LLM call. The Memory API is high-level and opinionated. For a more customizable, low-level way to add and retrieve memory, see the [Graph API](/understanding-the-graph). ## Adding memory Add your chat history to Zep using the `memory.add` method. `memory.add` is session-specific and expects data in chat message format, including a `role` name (e.g., user's real name), `role_type` (AI, human, tool), and message `content`. Zep stores the chat history and builds a user-level knowledge graph from the messages. For best results, add chat history to Zep on every chat turn. That is, add both the AI and human messages in a single operation and in the order that the messages were created. The example below adds messages to Zep's memory for the user in the given session: ```python Python from zep_cloud.client import AsyncZep from zep_cloud.types import Message zep_client = AsyncZep( api_key=API_KEY, ) messages = [ Message( role="Jane", role_type="user", content="Who was Octavia Butler?", ) ] await zep_client.memory.add(session_id, messages=messages) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; import type { Message } from "@getzep/zep-cloud/api"; const zepClient = new ZepClient({ apiKey: API_KEY, }); const messages: Message[] = [ { role: "Jane", role_type: "user", content: "Who was Octavia Butler?" }, ]; await zepClient.memory.add(sessionId, { messages }); ``` ```go Go import ( "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) zepClient := zepclient.NewClient( option.WithAPIKey(""), ) response, err := zepClient.Memory.Add( context.TODO(), "sessionId", &zepgo.AddMemoryRequest{ Messages: []*zepgo.Message{ &zepgo.Message{ Role: "Jane", RoleType: "user", Content: "Who was Octavia Butler?", }, }, }, ) ``` You can find additional arguments to `memory.add` in the [SDK reference](/sdk-reference/memory/add). Notably, for latency sensitive applications, you can set `return_context` to true which will make `memory.add` return a context string in the way that `memory.get` does (discussed below). If you are looking to add JSON or unstructured text as memory to the graph, you will need to use our [Graph API](/adding-data-to-the-graph). ### Ignore assistant messages You can also pass in a list of role types to ignore when adding data to the graph using the `ignore_roles` argument. For example, you may not want assistant messages to be added to the user graph; providing the assistant messages in the `memory.add` call while setting `ignore_roles` to include "assistant" will make it so that only the user messages are ingested into the graph, but the assistant messages are still used to contextualize the user messages. This is important in case the user message itself does not have enough context, such as the message "Yes." Additionally, the assistant messages will still be added to the session's message history. ## Retrieving memory The `memory.get()` method is a user-friendly, high-level API for retrieving relevant context from Zep. It uses the latest messages of the *given session* to determine what information is most relevant from the user's knowledge graph and returns that information in a [context string](/concepts#memory-context) for your prompt. Note that although `memory.get()` only requires a session ID, it is able to return memory derived from any session of that user. The session is just used to determine what's relevant. `memory.get` also returns recent chat messages and raw facts that may provide additional context for your agent. We recommend using these raw messages when you call your LLM provider (see below). The `memory.get` method is user and session-specific and cannot retrieve data from group graphs. The example below gets the `memory.context` string for the given session: ```python Python memory = zep_client.memory.get(session_id="session_id") # the context field described above context = memory.context ``` ```typescript TypeScript const memory = await zep_client.memory.get("sessionId"); // the context field described above const context = memory.context; ``` ```go Go memory, err := zep_client.Memory.Get(context.TODO(), "sessionId", nil) // the context field described above context := memory.Context ``` You can find additional arguments to `memory.get` in the [SDK reference](/sdk-reference/memory/get). Notably, you can specify a minimum [fact rating](/facts#rating-facts-for-relevancy) which will filter out any retrieved facts with a rating below the threshold, if you are using fact ratings. If you are looking to customize how memory is retrieved, you will need to [search the graph](/searching-the-graph) and construct a [custom memory context string](/cookbook/customize-your-memory-context-string). For example, `memory.get` uses the last few messages as the search query on the graph, but using the graph API you can use whatever query you want, as well as experiment with other search parameters such as re-ranker used. ## Using memory Once you've retrieved the [memory context string](/concepts#memory-context), or [constructed your own context string](/cookbook/customize-your-memory-context-string) by [searching the graph](/searching-the-graph), you can include this string in your system prompt: | MessageType | Content | | ----------- | ------------------------------------------------------- | | `System` | Your system prompt

`{Zep context string}` | | `Assistant` | An assistant message stored in Zep | | `User` | A user message stored in Zep | | ... | ... | | `User` | The latest user message | You should also include the last 4 to 6 messages of the session when calling your LLM provider. Because Zep's ingestion can take a few minutes, the context string may not include information from the last few messages; and so the context string acts as the "long-term memory," and the last few messages serve as the raw, short-term memory. In latency sensitive applications such as voice chat bots, you can use the context string returned from `memory.add` to avoid making two API calls. ## Customizing memory The Memory API is our high level, easy-to-use API for adding and retrieving memory. If you want to add business data or documents to memory, or further customize how memory is retrieved, you should refer to our Guides on using the graph, such as [adding data to the graph](/adding-data-to-the-graph) and [searching the graph](/searching-the-graph). We also have a cookbook on [creating a custom context string](/cookbook/customize-your-memory-context-string) using the graph API. Additionally, [group graphs](/groups) can be used to store non-user-specific memory. # Projects API keys are specific to a project. You can create multiple keys for a single project. Visit `Project Settings` in the Zep dashboard to manage your API keys. Projects bundle elements like Users, Sessions, Groups, Knowledge Graphs, and settings, helping you organize data by service, environment (e.g., development or production), or other relevant criteria. ## Creating a Project When you sign up for Zep, your first project is automatically created. You'll be asked to configure a few project-specific settings (details below). If you need more projects, you can create them anytime through the Zep Web App. Create a new project ### Project Essentials * Unique Project Name: Choose a unique name for your project. * Description (Optional): Optionally add a brief description of your project. > **You can modify your project settings later from the Dashboard.** # Users A User represents an individual interacting with your application. Each User can have multiple Sessions associated with them, allowing you to track and manage their interactions over time. The unique identifier for each user is their `UserID`. This can be any string value, such as a username, email address, or UUID. The User object and its associated Sessions provide a powerful way to manage and understand user behavior. By associating Sessions with Users, you can track the progression of conversations and interactions over time, providing valuable context and history. In the following sections, you will learn how to manage Users and their associated Sessions. **Users Enable Simple User Privacy Management** Deleting a User will delete all Sessions and session artifacts associated with that User with a single API call, making it easy to handle Right To Be Forgotten requests. ## Ensuring your User data is correctly mapped to the Zep knowledge graph Adding your user's `email`, `first_name`, and `last_name` ensures that chat messages and business data are correctly mapped to the user node in the Zep knowledge graph. For e.g., if business data contains your user's email address, it will be related directly to the user node. You can associate rich business context with a User: * `user_id`: A unique identifier of the user that maps to your internal User ID. * `email`: The user's email. * `first_name`: The user's first name. * `last_name`: The user's last name. ## Adding a User You can add a new user by providing the user details. ```python Python from zep_cloud.client import Zep client = Zep(api_key=API_KEY) new_user = client.user.add( user_id=user_id, email="[email protected]", first_name="Jane", last_name="Smith", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const user = await client.user.add({ userId: user_id, email: "[email protected]", firstName: "Jane", lastName: "Smith", }); ``` > Learn how to associate [Sessions with Users](/sessions) ## Getting a User You can retrieve a user by their ID. ```python Python user = client.user.get("user123") ``` ```typescript TypeScript const user = await client.user.get("user123"); ``` ## Updating a User You can update a user's details by providing the updated user details. ```python Python updated_user = client.user.update( user_id=user_id, email="[email protected]", first_name="Jane", last_name="Smith", ) ``` ```typescript TypeScript const updated_user = await client.user.update(user_id, { email: "[email protected]", firstName: "Jane", lastName: "Smith", metadata: { foo: "updated_bar" }, }); ``` ## Deleting a User You can delete a user by their ID. ```python Python client.user.delete("user123") ``` ```typescript TypeScript await client.user.delete("user123"); ``` ## Getting a User's Sessions You can retrieve all Sessions for a user by their ID. ```python Python sessions = client.user.get_sessions("user123") ``` ```typescript TypeScript const sessions = await client.user.getSessions("user123"); ``` ## Listing Users You can list all users, with optional limit and cursor parameters for pagination. ```python Python # List the first 10 users result = client.user.list_ordered(page_size=10, page_number=1) ``` ```typescript TypeScript // List the first 10 users const result = await client.user.listOrdered({ pageSize: 10, pageNumber: 1, }); ``` ## Get the User Node You can also retrieve the user's node from their graph: ```python Python results = client.user.get_node(user_id=user_id) user_node = results.node print(user_node.summary) ``` ```typescript TypeScript const results = await client.user.getNode(userId); const userNode = results.node; console.log(userNode?.summary); ``` The user node might be used to get a summary of the user or to get facts related to the user (see ["How to find facts relevant to a specific node"](/cookbook/how-to-find-facts-relevant-to-a-specific-node)). # Sessions Sessions represent a conversation. Each [User](/users) can have multiple sessions, and each session is a sequence of chat messages. Chat messages are added to sessions using [`memory.add`](/concepts#using-memoryadd), which both adds those messages to the session history and ingests those messages into the user-level knowledge graph. The user knowledge graph contains data from all of that user's sessions to create an integrated understanding of the user. The knowledge graph does not separate the data from different sessions, but integrates the data together to create a unified picture of the user. So the [get session memory](/sdk-reference/memory/get) endpoint and the associated [`memory.get`](/concepts#using-memoryget) method don't return memory derived only from that session, but instead return whatever user-level memory is most relevant to that session, based on the session's most recent messages. ## Adding a Session `SessionIDs` are arbitrary identifiers that you can map to relevant business objects in your app, such as users or a conversation a user might have with your app. Before you create a session, make sure you have [created a user](/users#adding-a-user) first. Then create a session with: ```python Python client = Zep( api_key=API_KEY, ) session_id = uuid.uuid4().hex # A new session identifier client.memory.add_session( session_id=session_id, user_id=user_id, ) ``` ```typescript TypeScript const client = new ZepClient({ apiKey: API_KEY, }); const sessionId: string = uuid.v4(); // Generate a new session identifier await client.memory.addSession({ sessionId: session_id, userId: userId, }); ``` ## Getting a Session ```python Python session = client.memory.get_session(session_id) print(session.dict()) ``` ```typescript TypeScript const session = await client.memory.getSession(sessionId); console.log(session); ``` ## Deleting a Session Deleting a session deletes it and its associated messages. It does not however delete the associated data in the user's knowledge graph. To remove data from the graph, see [deleting data from the graph](/deleting-data-from-the-graph). ```python Python client.memory.delete(session_id) ``` ```typescript TypeScript await client.memory.delete(sessionId); ``` ## Listing Sessions You can list all Sessions in the Zep Memory Store with page\_size and page\_number parameters for pagination. ```python Python # List the first 10 Sessions result = client.memory.list_sessions(page_size=10, page_number=1) for session in result.sessions: print(session) ``` ```typescript TypeScript // List the first 10 Sessions const { sessions } = await client.memory.listSessions({ pageSize: 10, pageNumber: 1, }); console.log("First 10 Sessions:"); sessions.forEach((session) => console.log(session)); ``` # Groups > Group graphs can be used to create and manage additional non-user specific graphs. A user graph is tied to a specific user; a group graph is just like a user graph, except it is not tied to a specific user. It is best thought of as an "arbitrary graph" which, for example, can be used as memory for a group of users, or for a more complex use case. For example, a group graph could store information about a company's product, which you might not want to add to every user's graph, because that would be redundant. And when your chatbot responds, it could utilize a memory context string from both that user's graph as well as from the product group graph. See our [cookbook on this](/cookbook/how-to-share-memory-across-users-using-group-graphs) for an example. A more complicated use case could be to create a group graph which is used when a certain topic is mentioned as opposed to when certain users require a response. For instance, anytime any user mentions "pizza" in a chat, that could trigger a call to a group graph about pizza. You do not need to add/register users with a group. Instead, you just retrieve memory from the group graph when responding to any of the users you want in the group. ## Creating a Group ```python Python group = client.group.add( group_id="some-group-id", description="This is a description.", name="Group Name" ) ``` ```typescript TypeScript const group = await client.group.add({ groupId: "some-group-id", description: "This is a description.", name: "Group Name" }); ``` ## Adding Data to a Group Graph Adding data to a group graph requires using the `graph.add` method. Below is an example, and for more on this method, see [Adding Data to the Graph](/adding-data-to-the-graph) and our [SDK Reference](/sdk-reference/graph/add). ```python Python client.graph.add( group_id=group_id, data="Hello world!", type="text", ) ``` ```typescript TypeScript await client.graph.add({ groupId: "some-group-id", data: "Hello world!", type: "text", }); ``` ## Searching a Group Graph Searching a group graph requires using the `graph.search` method. Below is an example, and for more on this method, see [Searching the Graph](/searching-the-graph) and our [SDK Reference](/sdk-reference/graph/search). ```python Python search_results = client.graph.search( group_id=group_id, query="Banana", scope="nodes", ) ``` ```typescript TypeScript const searchResults = await client.graph.search({ groupId: groupId, query: "Banana", scope: "nodes", }); ``` ## Deleting a Group ```python Python client.group.delete(group_id) ``` ```typescript TypeScript await client.group.delete("some-group-id"); ``` # Understanding the Graph Zep's temporal knowledge graph powers its context engineering capabilities, including agent memory and Graph RAG. Zep's graph is built on [Graphiti](/graphiti/graphiti/overview), Zep's open-source temporal graph library, which is fully integrated into Zep. Developers do not need to interact directly with Graphiti or understand its underlying implementation. Zep's graph database stores data in three main types: 1. Entity edges (edges): Represent relationships between nodes and include semantic facts representing the relationship between the edge's nodes. 2. Entity nodes (nodes): Represent entities extracted from episodes, containing summaries of relevant information. 3. Episodic nodes (episodes): Represent raw data stored in Zep, either through chat history or the `graph.add` endpoint. ## Working with the Graph To learn more about interacting with Zep's graph, refer to the following sections: * [Adding Data to the Graph](/adding-data-to-the-graph): Learn how to add new data to the graph. * [Reading Data from the Graph](/reading-data-from-the-graph): Discover how to retrieve information from the graph. * [Searching the Graph](/searching-the-graph): Explore techniques for efficiently searching the graph. These guides will help you leverage the full power of Zep's knowledge graph in your applications. # Utilizing Facts and Summaries > Facts and summaries are extracted from the chat history as a conversation unfolds as well as from business data added to Zep. ## Understanding Facts and Summaries in Zep ### Facts are Precise and Time-Stamped Information A `fact` is stored on an [edge](/sdk-reference/graph/edge/get) and captures a detailed relationship about specific events. It includes `valid_at` and `invalid_at` timestamps, ensuring temporal accuracy and preserving a clear history of changes over time. This makes facts reliable sources of truth for critical information retrieval, providing the authoritative context needed for accurate decision-making and analysis by your agent. ### Summaries are High-Level Overviews of Entities or Concepts A `summary` resides on a [node](/sdk-reference/graph/node/get) and provides a broad snapshot of an entity or concept and its relationships to other nodes. Summaries offer an aggregated and concise representation, making it easier to understand key information at a glance. Zep does not recommend relying solely on summaries for grounding LLM responses. While summaries provide a high-level overview, they lack the temporal accuracy necessary for precise reasoning. Instead, the [memory context](/concepts#memory-context) should be used since it includes relevant facts (each with valid and invalid timestamps). This ensures that conversations are based on up-to-date and contextually accurate information. ## Context String When calling [Get Session Memory](/sdk-reference/memory/get), Zep employs a sophisticated search strategy to surface the most pertinent information. The system first examines recent context by analyzing the last 4 messages (2 complete chat turns). It then utilizes multiple search techniques, with reranking steps to identify and prioritize the most contextually significant details for the current conversation. The returned, `context` is structured as a string, optimized for language model prompts, making it easy to integrate into AI workflows. For more details, see [Key Concepts](/concepts#memory-context). In addition to the `context`, the API response includes an array of the identified `relevant_facts` with their supporting details. ## Rating Facts for Relevancy Not all `relevant_facts` are equally important to your specific use-case. For example, a relationship coach app may need to recall important facts about a user’s family, but what the user ate for breakfast Friday last week is unimportant. Fact ratings are a way to help Zep understand the importance of `relevant_facts` to your particular use case. After implementing fact ratings, you can specify a `minRating` when retrieving `relevant_facts` from Zep, ensuring that the memory `context` string contains customized content. ### Implementing Fact Ratings The `fact_rating_instruction` framework consists of an instruction and three example facts, one for each of a `high`, `medium`, and `low` rating. These are passed when [Adding a User](/sdk-reference/user/add) or [Adding a Group](/sdk-reference/group/add) and become a property of the User or Group. ### Example: Fact Rating Implementation ```python Rating Facts for Poignancy fact_rating_instruction = """Rate the facts by poignancy. Highly poignant facts have a significant emotional impact or relevance to the user. Facts with low poignancy are minimally relevant or of little emotional significance.""" fact_rating_examples = FactRatingExamples( high="The user received news of a family member's serious illness.", medium="The user completed a challenging marathon.", low="The user bought a new brand of toothpaste.", ) client.user.add( user_id=user_id, fact_rating_instruction=FactRatingInstruction( instruction=fact_rating_instruction, examples=fact_rating_examples, ), ) ``` ```python Use Case-Specific Fact Rating client.user.add( user_id=user_id, fact_rating_instruction=FactRatingInstruction( instruction="""Rate the facts by how relevant they are to purchasing shoes.""", examples=FactRatingExamples( high="The user has agreed to purchase a Reebok running shoe.", medium="The user prefers running to cycling.", low="The user purchased a dress.", ), ), ) ``` All facts are rated on a scale between 0 and 1. You can access `rating` when retrieving `relevant_facts` from [Get Session Memory](/sdk-reference/memory/get). ### Limiting Memory Recall to High-Rating Facts You can filter `relevant_facts` by setting the `minRating` parameter in [Get Session Memory](/sdk-reference/memory/get). ```python result = client.memory.get(session_id, min_rating=0.7) ``` ## Adding or Deleting Facts or Summaries Facts and summaries are generated as part of the ingestion process. If you follow the directions for [adding data to the graph](/adding-data-to-the-graph), new facts and summaries will be created. Deleting facts and summaries is handled by deleting data from the graph. Facts and summaries will be deleted when you [delete the edge or node](/deleting-data-from-the-graph) they exist on. ## APIs related to Facts and Summaries You can extract facts and summaries using the following methods: | Method | Description | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | | [Get Session Memory](/sdk-reference/memory/get) | Retrieves the `context` string and `relevant_facts` | | [Add User](/sdk-reference/user/add)
[Update User](/sdk-reference/user/update)
[Create Group](/sdk-reference/group/add)
[Update Group](/sdk-reference/group/update) | Allows specifying `fact_rating_instruction` | | [Get User](/sdk-reference/user/get)
[Get Users](/sdk-reference/user/list-ordered)
[Get Group](/sdk-reference/group/get-group)
[Get All Groups](/sdk-reference/group/get-all-groups) | Retrieves `fact_rating_instruction` for each user or group | | [Search the Graph](/sdk-reference/graph/search) | Returns a list. Each item is an `edge` or `node` and has an associated `fact` or `summary` | | [Get User Edges](/sdk-reference/graph/edge/get-by-user-id)
[Get Group Edges](/sdk-reference/graph/edge/get-by-group-id)
[Get Edge](/sdk-reference/graph/edge/get) | Retrieves `fact` on each `edge` | | [Get User Nodes](/sdk-reference/graph/node/get-by-user-id)
[Get Group Nodes](/sdk-reference/graph/node/get-by-group-id)
[Get Node](/sdk-reference/graph/node/get) | Retrieves `summary` on each `node` | # Customizing Graph Structure Zep enables the use of rich, domain-specific data structures in graphs through Entity Types and Edge Types, replacing generic graph nodes and edges with detailed models. Zep classifies newly created nodes/edges as one of the default or custom types or leaves them unclassified. For example, a node representing a preference is classified as a Preference node, and attributes specific to that type are automatically populated. You may restrict graph queries to nodes/edges of a specific type, such as Preference. The default entity types are applied to all graphs by default, but you may define additional custom types as needed. Each node/edge is classified as a single type only. Multiple classifications are not supported. ## Default Entity Types ### Definition The default entity types are: * **User**: A human that is part of the current chat thread. * **Preference**: One of the User's preferences. * **Procedure**: A multi-step instruction informing the agent how to behave (e.g. 'When the user asks for code, respond only with code snippets followed by a bullet point explanation') Default entity types only apply to user graphs (not group graphs). All nodes in any user graph will be classified into one of these types or none. ### Adding Data When we add data to the graph, default entity types are automatically created: ```python from zep_cloud.types import Message message = {"role": "John Doe", "role_type": "user", "content": "I really like pop music, and I don't like metal"} client.memory.add(session_id=session_id, messages=[Message(**message)]) ``` ```typescript import { RoleType } from "@getzep/zep-cloud/api/types"; const messages = [{ role: "John Doe", roleType: RoleType.UserRole, content: "I really like pop music, and I don't like metal" }]; await client.memory.add(sessionId, {messages: messages}); ``` ```go userRole := "John Doe" messages := []*zep.Message{ { Role: &userRole, Content: "I really like pop music, and I don't like metal", RoleType: "user", }, } // Add the messages to the graph _, err = client.Memory.Add( context.TODO(), sessionID, &zep.AddMemoryRequest{ Messages: messages, }, ) if err != nil { log.Fatal("Error adding messages:", err) } ``` ### Searching When searching nodes in the graph, you may provide a list of types to filter the search by. The provided types are ORed together. Search results will only include nodes that satisfy one of the provided types: ```python search_results = client.graph.search( user_id=user_id, query="the user's music preferences", scope="nodes", search_filters={ "node_labels": ["Preference"] } ) for i, node in enumerate(search_results.nodes): preference = node.attributes print(f"Preference {i+1}:{preference}") ``` ```typescript const searchResults = await client.graph.search({ userId: userId, query: "the user's music preferences", scope: "nodes", searchFilters: { nodeLabels: ["Preference"], }, }); if (searchResults.nodes && searchResults.nodes.length > 0) { for (let i = 0; i < searchResults.nodes.length; i++) { const node = searchResults.nodes[i]; const preference = node.attributes; console.log(`Preference ${i + 1}: ${JSON.stringify(preference)}`); } } ``` ```go searchFilters := zep.SearchFilters{NodeLabels: []string{"Preference"}} searchResults, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "the user's music preferences", Scope: zep.GraphSearchScopeNodes.Ptr(), SearchFilters: &searchFilters, }, ) if err != nil { log.Fatal("Error searching graph:", err) } for i, node := range searchResults.Nodes { // Convert attributes map to JSON for pretty printing attributesJSON, err := json.MarshalIndent(node.Attributes, "", " ") if err != nil { log.Fatal("Error marshaling attributes:", err) } fmt.Printf("Preference %d:\n%s\n\n", i+1, string(attributesJSON)) } ``` ```text Preference 1: {'category': 'Music', 'description': 'Pop Music is a genre of music characterized by its catchy melodies and widespread appeal.', 'labels': ['Entity', 'Preference']} Preference 2: {'category': 'Music', 'description': 'Metal Music is a genre of music characterized by its heavy sound and complex compositions.', 'labels': ['Entity', 'Preference']} ``` ## Custom Entity and Edge Types Start with fewer, more generic custom types with minimal fields and simple definitions, then incrementally add complexity as needed. This functionality requires prompt engineering and iterative optimization of the class and field descriptions, so it's best to start simple. ### Definition In addition to the default entity types, you may specify your own custom entity and custom edge types. You need to provide a description of the type and a description for each of the fields. The syntax for this is different for each language. You may not create more than 10 custom entity types and 10 custom edge types per project. The limit of 10 custom entity types does not include the default types. Each model may have up to 10 fields. When creating custom entity or edge types, you may not use the following attribute names (including in Go struct tags), as they conflict with default node attributes: `uuid`, `name`, `group_id`, `name_embedding`, `summary`, and `created_at`. Including attributes on custom entity and edge types is an advanced feature designed for precision context engineering where you only want to utilize specific field values when constructing your context string. [See here for an example](/cookbooks/customizing-memory-context-string#example-2-using-custom-entity-and-edge-attributes). Many agent memory use cases can be solved with node summaries and facts alone. Custom attributes should only be added when you need structured field values for precise context retrieval rather than general conversational memory. ```python from zep_cloud.external_clients.ontology import EntityModel, EntityText, EdgeModel, EntityBoolean from pydantic import Field class Restaurant(EntityModel): """ Represents a specific restaurant. """ cuisine_type: EntityText = Field(description="The cuisine type of the restaurant, for example: American, Mexican, Indian, etc.", default=None) dietary_accommodation: EntityText = Field(description="The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc.", default=None) class Audiobook(EntityModel): """ Represents an audiobook entity. """ genre: EntityText = Field(description="The genre of the audiobook, for example: self-help, fiction, nonfiction, etc.", default=None) class RestaurantVisit(EdgeModel): """ Represents the fact that the user visited a restaurant. """ restaurant_name: EntityText = Field(description="The name of the restaurant the user visited", default=None) class AudiobookListen(EdgeModel): """ Represents the fact that the user listened to or played an audiobook. """ audiobook_title: EntityText = Field(description="The title of the audiobook the user listened to or played", default=None) class DietaryPreference(EdgeModel): """ Represents the fact that the user has a dietary preference or dietary restriction. """ preference_type: EntityText = Field(description="Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc.", default=None) allergy: EntityBoolean = Field(description="Whether this dietary preference represents a user allergy: True or false", default=None) ``` ```typescript import { entityFields, EntityType, EdgeType } from "@getzep/zep-cloud/wrapper/ontology"; const RestaurantSchema: EntityType = { description: "Represents a specific restaurant.", fields: { cuisine_type: entityFields.text("The cuisine type of the restaurant, for example: American, Mexican, Indian, etc."), dietary_accommodation: entityFields.text("The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc."), }, }; const AudiobookSchema: EntityType = { description: "Represents an audiobook entity.", fields: { genre: entityFields.text("The genre of the audiobook, for example: self-help, fiction, nonfiction, etc."), }, }; const RestaurantVisit: EdgeType = { description: "Represents the fact that the user visited a restaurant.", fields: { restaurant_name: entityFields.text("The name of the restaurant the user visited"), }, sourceTargets: [ { source: "User", target: "Restaurant" }, ], }; const AudiobookListen: EdgeType = { description: "Represents the fact that the user listened to or played an audiobook.", fields: { audiobook_title: entityFields.text("The title of the audiobook the user listened to or played"), }, sourceTargets: [ { source: "User", target: "Audiobook" }, ], }; const DietaryPreference: EdgeType = { description: "Represents the fact that the user has a dietary preference or dietary restriction.", fields: { preference_type: entityFields.text("Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc."), allergy: entityFields.boolean("Whether this dietary preference represents a user allergy: True or false"), }, sourceTargets: [ { source: "User" }, ], }; ``` ```go type Restaurant struct { zep.BaseEntity `name:"Restaurant" description:"Represents a specific restaurant."` CuisineType string `description:"The cuisine type of the restaurant, for example: American, Mexican, Indian, etc." json:"cuisine_type,omitempty"` DietaryAccommodation string `description:"The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc." json:"dietary_accommodation,omitempty"` } type Audiobook struct { zep.BaseEntity `name:"Audiobook" description:"Represents an audiobook entity."` Genre string `description:"The genre of the audiobook, for example: self-help, fiction, nonfiction, etc." json:"genre,omitempty"` } type RestaurantVisit struct { zep.BaseEdge `name:"RESTAURANT_VISIT" description:"Represents the fact that the user visited a restaurant."` RestaurantName string `description:"The name of the restaurant the user visited" json:"restaurant_name,omitempty"` } type AudiobookListen struct { zep.BaseEdge `name:"AUDIOBOOK_LISTEN" description:"Represents the fact that the user listened to or played an audiobook."` AudiobookTitle string `description:"The title of the audiobook the user listened to or played" json:"audiobook_title,omitempty"` } type DietaryPreference struct { zep.BaseEdge `name:"DIETARY_PREFERENCE" description:"Represents the fact that the user has a dietary preference or dietary restriction."` PreferenceType string `description:"Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc." json:"preference_type,omitempty"` Allergy bool `description:"Whether this dietary preference represents a user allergy: True or false" json:"allergy,omitempty"` } ``` ### Setting Entity and Edge Types You can then set these custom entity and edge types as the graph ontology for your current [Zep project](/projects). Note that for custom edge types, you can require the source and destination nodes to be a certain type, or allow them to be any type: ```python from zep_cloud import EntityEdgeSourceTarget client.graph.set_ontology( entities={ "Restaurant": Restaurant, "Audiobook": Audiobook, }, edges={ "RESTAURANT_VISIT": ( RestaurantVisit, [EntityEdgeSourceTarget(source="User", target="Restaurant")] ), "AUDIOBOOK_LISTEN": ( AudiobookListen, [EntityEdgeSourceTarget(source="User", target="Audiobook")] ), "DIETARY_PREFERENCE": ( DietaryPreference, [EntityEdgeSourceTarget(source="User")] ), } ) ``` ```typescript await client.graph.setOntology( { Restaurant: RestaurantSchema, Audiobook: AudiobookSchema, }, { RESTAURANT_VISIT: RestaurantVisit, AUDIOBOOK_LISTEN: AudiobookListen, DIETARY_PREFERENCE: DietaryPreference, } ); ``` ```go _, err = client.Graph.SetOntology( ctx, []zep.EntityDefinition{ Restaurant{}, Audiobook{}, }, []zep.EdgeDefinitionWithSourceTargets{ { EdgeModel: RestaurantVisit{}, SourceTargets: []zep.EntityEdgeSourceTarget{ { Source: zep.String("User"), Target: zep.String("Restaurant"), }, }, }, { EdgeModel: AudiobookListen{}, SourceTargets: []zep.EntityEdgeSourceTarget{ { Source: zep.String("User"), Target: zep.String("Audiobook"), }, }, }, { EdgeModel: DietaryPreference{}, SourceTargets: []zep.EntityEdgeSourceTarget{ { Source: zep.String("User"), }, }, }, }, ) if err != nil { fmt.Printf("Error setting ontology: %v\n", err) return } ``` ### Adding Data Now, when you add data to the graph, new nodes and edges are classified into exactly one of the overall set of entity or edge types respectively, or no type: ```python from zep_cloud import Message import uuid messages_session1 = [ Message(content="Take me to a lunch place", role_type="user", role="John Doe"), Message(content="How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", role_type="assistant", role="Assistant"), Message(content="Do any of those have vegetarian options? I'm vegetarian", role_type="user", role="John Doe"), Message(content="Yes, Green Leaf Cafe has vegetarian options", role_type="assistant", role="Assistant"), Message(content="Let's go to Green Leaf Cafe", role_type="user", role="John Doe"), Message(content="Navigating to Green Leaf Cafe", role_type="assistant", role="Assistant"), ] messages_session2 = [ Message(content="Play the 7 habits of highly effective people", role_type="user", role="John Doe"), Message(content="Playing the 7 habits of highly effective people", role_type="assistant", role="Assistant"), ] user_id = f"user-{uuid.uuid4()}" client.user.add(user_id=user_id, first_name="John", last_name="Doe", email="[email protected]") session1_id = f"session-{uuid.uuid4()}" session2_id = f"session-{uuid.uuid4()}" client.memory.add_session(session_id=session1_id, user_id=user_id) client.memory.add_session(session_id=session2_id, user_id=user_id) client.memory.add(session_id=session1_id, messages=messages_session1, ignore_roles=["assistant"]) client.memory.add(session_id=session2_id, messages=messages_session2, ignore_roles=["assistant"]) ``` ```typescript import { v4 as uuidv4 } from "uuid"; import type { Message } from "@getzep/zep-cloud/api"; const messagesSession1: Message[] = [ { content: "Take me to a lunch place", roleType: "user", role: "John Doe" }, { content: "How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", roleType: "assistant", role: "Assistant" }, { content: "Do any of those have vegetarian options? I'm vegetarian", roleType: "user", role: "John Doe" }, { content: "Yes, Green Leaf Cafe has vegetarian options", roleType: "assistant", role: "Assistant" }, { content: "Let's go to Green Leaf Cafe", roleType: "user", role: "John Doe" }, { content: "Navigating to Green Leaf Cafe", roleType: "assistant", role: "Assistant" }, ]; const messagesSession2: Message[] = [ { content: "Play the 7 habits of highly effective people", roleType: "user", role: "John Doe" }, { content: "Playing the 7 habits of highly effective people", roleType: "assistant", role: "Assistant" }, ]; let userId = `user-${uuidv4()}`; await client.user.add({ userId, firstName: "John", lastName: "Doe", email: "[email protected]" }); const session1Id = `session-${uuidv4()}`; const session2Id = `session-${uuidv4()}`; await client.memory.addSession({ sessionId: session1Id, userId }); await client.memory.addSession({ sessionId: session2Id, userId }); await client.memory.add(session1Id, { messages: messagesSession1, ignoreRoles: ["assistant"] }); await client.memory.add(session2Id, { messages: messagesSession2, ignoreRoles: ["assistant"] }); ``` ```go messagesSession1 := []zep.Message{ {Content: "Take me to a lunch place", RoleType: "user", Role: zep.String("John Doe")}, {Content: "How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "Do any of those have vegetarian options? I'm vegetarian", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Yes, Green Leaf Cafe has vegetarian options", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "Let's go to Green Leaf Cafe", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Navigating to Green Leaf Cafe", RoleType: "assistant", Role: zep.String("Assistant")}, } messagesSession2 := []zep.Message{ {Content: "Play the 7 habits of highly effective people", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Playing the 7 habits of highly effective people", RoleType: "assistant", Role: zep.String("Assistant")}, } userID := "user-" + uuid.NewString() userReq := &zep.CreateUserRequest{ UserID: userID, FirstName: zep.String("John"), LastName: zep.String("Doe"), Email: zep.String("[email protected]"), } _, err = client.User.Add(ctx, userReq) if err != nil { fmt.Printf("Error creating user: %v\n", err) return } session1ID := "session-" + uuid.NewString() session2ID := "session-" + uuid.NewString() session1Req := &zep.CreateSessionRequest{ SessionID: session1ID, UserID: userID, } session2Req := &zep.CreateSessionRequest{ SessionID: session2ID, UserID: userID, } _, err = client.Memory.AddSession(ctx, session1Req) if err != nil { fmt.Printf("Error creating session 1: %v\n", err) return } _, err = client.Memory.AddSession(ctx, session2Req) if err != nil { fmt.Printf("Error creating session 2: %v\n", err) return } msgPtrs1 := make([]*zep.Message, len(messagesSession1)) for i := range messagesSession1 { msgPtrs1[i] = &messagesSession1[i] } addReq1 := &zep.AddMemoryRequest{ Messages: msgPtrs1, IgnoreRoles: []zep.RoleType{ zep.RoleTypeAssistantRole, }, } _, err = client.Memory.Add(ctx, session1ID, addReq1) if err != nil { fmt.Printf("Error adding messages to session 1: %v\n", err) return } msgPtrs2 := make([]*zep.Message, len(messagesSession2)) for i := range messagesSession2 { msgPtrs2[i] = &messagesSession2[i] } addReq2 := &zep.AddMemoryRequest{ Messages: msgPtrs2, IgnoreRoles: []zep.RoleType{ zep.RoleTypeAssistantRole, }, } _, err = client.Memory.Add(ctx, session2ID, addReq2) if err != nil { fmt.Printf("Error adding messages to session 2: %v\n", err) return } ``` ### Searching/Retrieving Now that a graph with custom entity and edge types has been created, you may filter node search results by entity type, or edge search results by edge type. Below, you can see the examples that were created from our data of each of the entity and edge types that we defined: ```python search_results_restaurants = client.graph.search( user_id=user_id, query="Take me to a restaurant", scope="nodes", search_filters={ "node_labels": ["Restaurant"] }, limit=1, ) node = search_results_restaurants.nodes[0] print(f"Node name: {node.name}") print(f"Node labels: {node.labels}") print(f"Cuisine type: {node.attributes.get('cuisine_type')}") print(f"Dietary accommodation: {node.attributes.get('dietary_accommodation')}") ``` ```typescript let searchResults = await client.graph.search({ userId: userId, query: "Take me to a restaurant", scope: "nodes", searchFilters: { nodeLabels: ["Restaurant"] }, limit: 1, }); if (searchResults.nodes && searchResults.nodes.length > 0) { const node = searchResults.nodes[0]; console.log(`Node name: ${node.name}`); console.log(`Node labels: ${node.labels}`); console.log(`Cuisine type: ${node.attributes?.cuisine_type}`); console.log(`Dietary accommodation: ${node.attributes?.dietary_accommodation}`); } ``` ```go searchFiltersRestaurants := zep.SearchFilters{NodeLabels: []string{"Restaurant"}} searchResultsRestaurants, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Take me to a restaurant", Scope: zep.GraphSearchScopeNodes.Ptr(), SearchFilters: &searchFiltersRestaurants, Limit: zep.Int(1), }, ) if err != nil { fmt.Printf("Error searching graph (Restaurant node): %v\n", err) return } if len(searchResultsRestaurants.Nodes) > 0 { node := searchResultsRestaurants.Nodes[0] fmt.Printf("Node name: %s\n", node.Name) fmt.Printf("Node labels: %v\n", node.Labels) fmt.Printf("Cuisine type: %v\n", node.Attributes["cuisine_type"]) fmt.Printf("Dietary accommodation: %v\n", node.Attributes["dietary_accommodation"]) } ``` ```text Node name: Green Leaf Cafe Node labels: Entity,Restaurant Cuisine type: undefined Dietary accommodation: vegetarian ``` ```python search_results_audiobook_nodes = client.graph.search( user_id=user_id, query="Play an audiobook", scope="nodes", search_filters={ "node_labels": ["Audiobook"] }, limit=1, ) node = search_results_audiobook_nodes.nodes[0] print(f"Node name: {node.name}") print(f"Node labels: {node.labels}") print(f"Genre: {node.attributes.get('genre')}") ``` ```typescript searchResults = await client.graph.search({ userId: userId, query: "Play an audiobook", scope: "nodes", searchFilters: { nodeLabels: ["Audiobook"] }, limit: 1, }); if (searchResults.nodes && searchResults.nodes.length > 0) { const node = searchResults.nodes[0]; console.log(`Node name: ${node.name}`); console.log(`Node labels: ${node.labels}`); console.log(`Genre: ${node.attributes?.genre}`); } ``` ```go searchFiltersAudiobook := zep.SearchFilters{NodeLabels: []string{"Audiobook"}} searchResultsAudiobook, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Play an audiobook", Scope: zep.GraphSearchScopeNodes.Ptr(), SearchFilters: &searchFiltersAudiobook, Limit: zep.Int(1), }, ) if err != nil { fmt.Printf("Error searching graph (Audiobook node): %v\n", err) return } if len(searchResultsAudiobook.Nodes) > 0 { node := searchResultsAudiobook.Nodes[0] fmt.Printf("Node name: %s\n", node.Name) fmt.Printf("Node labels: %v\n", node.Labels) fmt.Printf("Genre: %v\n", node.Attributes["genre"]) } ``` ```text Node name: 7 habits of highly effective people Node labels: Entity,Audiobook Genre: undefined ``` ```python search_results_visits = client.graph.search( user_id=user_id, query="Take me to a restaurant", scope="edges", search_filters={ "edge_types": ["RESTAURANT_VISIT"] }, limit=1, ) edge = search_results_visits.edges[0] print(f"Edge fact: {edge.fact}") print(f"Edge type: {edge.name}") print(f"Restaurant name: {edge.attributes.get('restaurant_name')}") ``` ```typescript searchResults = await client.graph.search({ userId: userId, query: "Take me to a restaurant", scope: "edges", searchFilters: { edgeTypes: ["RESTAURANT_VISIT"] }, limit: 1, }); if (searchResults.edges && searchResults.edges.length > 0) { const edge = searchResults.edges[0]; console.log(`Edge fact: ${edge.fact}`); console.log(`Edge type: ${edge.name}`); console.log(`Restaurant name: ${edge.attributes?.restaurant_name}`); } ``` ```go searchFiltersVisits := zep.SearchFilters{EdgeTypes: []string{"RESTAURANT_VISIT"}} searchResultsVisits, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Take me to a restaurant", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersVisits, Limit: zep.Int(1), }, ) if err != nil { fmt.Printf("Error searching graph (RESTAURANT_VISIT): %v\n", err) return } if len(searchResultsVisits.Edges) > 0 { edge := searchResultsVisits.Edges[0] var visit RestaurantVisit err := zep.UnmarshalEdgeAttributes(edge.Attributes, &visit) if err != nil { fmt.Printf("\t\tError converting edge to RestaurantVisit struct: %v\n", err) } else { fmt.Printf("Edge fact: %s\n", edge.Fact) fmt.Printf("Edge type: %s\n", edge.Name) fmt.Printf("Restaurant name: %s\n", visit.RestaurantName) } } ``` ```text Edge fact: User John Doe is going to Green Leaf Cafe Edge type: RESTAURANT_VISIT Restaurant name: Green Leaf Cafe ``` ```python search_results_audiobook_listens = client.graph.search( user_id=user_id, query="Play an audiobook", scope="edges", search_filters={ "edge_types": ["AUDIOBOOK_LISTEN"] }, limit=1, ) edge = search_results_audiobook_listens.edges[0] print(f"Edge fact: {edge.fact}") print(f"Edge type: {edge.name}") print(f"Audiobook title: {edge.attributes.get('audiobook_title')}") ``` ```typescript searchResults = await client.graph.search({ userId: userId, query: "Play an audiobook", scope: "edges", searchFilters: { edgeTypes: ["AUDIOBOOK_LISTEN"] }, limit: 1, }); if (searchResults.edges && searchResults.edges.length > 0) { const edge = searchResults.edges[0]; console.log(`Edge fact: ${edge.fact}`); console.log(`Edge type: ${edge.name}`); console.log(`Audiobook title: ${edge.attributes?.audiobook_title}`); } ``` ```go searchFiltersAudiobookListen := zep.SearchFilters{EdgeTypes: []string{"AUDIOBOOK_LISTEN"}} searchResultsAudiobookListen, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Play an audiobook", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersAudiobookListen, Limit: zep.Int(1), }, ) if err != nil { fmt.Printf("Error searching graph (AUDIOBOOK_LISTEN): %v\n", err) return } if len(searchResultsAudiobookListen.Edges) > 0 { edge := searchResultsAudiobookListen.Edges[0] var listen AudiobookListen err := zep.UnmarshalEdgeAttributes(edge.Attributes, &listen) if err != nil { fmt.Printf("Error converting edge to AudiobookListen struct: %v\n", err) } else { fmt.Printf("Edge fact: %s\n", edge.Fact) fmt.Printf("Edge type: %s\n", edge.Name) fmt.Printf("Audiobook title: %s\n", listen.AudiobookTitle) } } ``` ```text Edge fact: John Doe requested to play the audiobook '7 habits of highly effective people' Edge type: AUDIOBOOK_LISTEN Audiobook title: 7 habits of highly effective people ``` ```python search_results_dietary_preference = client.graph.search( user_id=user_id, query="Find some food around here", scope="edges", search_filters={ "edge_types": ["DIETARY_PREFERENCE"] }, limit=1, ) edge = search_results_dietary_preference.edges[0] print(f"Edge fact: {edge.fact}") print(f"Edge type: {edge.name}") print(f"Preference type: {edge.attributes.get('preference_type')}") print(f"Allergy: {edge.attributes.get('allergy')}") ``` ```typescript searchResults = await client.graph.search({ userId: userId, query: "Find some food around here", scope: "edges", searchFilters: { edgeTypes: ["DIETARY_PREFERENCE"] }, limit: 1, }); if (searchResults.edges && searchResults.edges.length > 0) { const edge = searchResults.edges[0]; console.log(`Edge fact: ${edge.fact}`); console.log(`Edge type: ${edge.name}`); console.log(`Preference type: ${edge.attributes?.preference_type}`); console.log(`Allergy: ${edge.attributes?.allergy}`); } ``` ```go searchFiltersDietary := zep.SearchFilters{EdgeTypes: []string{"DIETARY_PREFERENCE"}} searchResultsDietary, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Find some food around here", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersDietary, Limit: zep.Int(1), }, ) if err != nil { fmt.Printf("Error searching graph (DIETARY_PREFERENCE): %v\n", err) return } if len(searchResultsDietary.Edges) > 0 { edge := searchResultsDietary.Edges[0] var dietary DietaryPreference err := zep.UnmarshalEdgeAttributes(edge.Attributes, &dietary) if err != nil { fmt.Printf("Error converting edge to DietaryPreference struct: %v\n", err) } else { fmt.Printf("Edge fact: %s\n", edge.Fact) fmt.Printf("Edge type: %s\n", edge.Name) fmt.Printf("Preference type: %s\n", dietary.PreferenceType) fmt.Printf("Allergy: %v\n", dietary.Allergy) } } ``` ```text Edge fact: User states 'I'm vegetarian' indicating a dietary preference. Edge type: DIETARY_PREFERENCE Preference type: vegetarian Allergy: false ``` Additionally, you can provide multiple types in search filters, and the types will be ORed together: ```python search_results_dietary_preference = client.graph.search( user_id=user_id, query="Find some food around here", scope="edges", search_filters={ "edge_types": ["DIETARY_PREFERENCE", "RESTAURANT_VISIT"] }, limit=2, ) for edge in search_results_dietary_preference.edges: print(f"Edge fact: {edge.fact}") print(f"Edge type: {edge.name}") if edge.name == "DIETARY_PREFERENCE": print(f"Preference type: {edge.attributes.get('preference_type')}") print(f"Allergy: {edge.attributes.get('allergy')}") elif edge.name == "RESTAURANT_VISIT": print(f"Restaurant name: {edge.attributes.get('restaurant_name')}") print("\n") ``` ```typescript searchResults = await client.graph.search({ userId: userId, query: "Find some food around here", scope: "edges", searchFilters: { edgeTypes: ["DIETARY_PREFERENCE", "RESTAURANT_VISIT"] }, limit: 2, }); if (searchResults.edges && searchResults.edges.length > 0) { for (const edge of searchResults.edges) { console.log(`Edge fact: ${edge.fact}`); console.log(`Edge type: ${edge.name}`); if (edge.name === "DIETARY_PREFERENCE") { console.log(`Preference type: ${edge.attributes?.preference_type}`); console.log(`Allergy: ${edge.attributes?.allergy}`); } else if (edge.name === "RESTAURANT_VISIT") { console.log(`Restaurant name: ${edge.attributes?.restaurant_name}`); } console.log("\n"); } } ``` ```go searchFiltersDietaryAndRestaurantVisit := zep.SearchFilters{EdgeTypes: []string{"DIETARY_PREFERENCE", "RESTAURANT_VISIT"}} searchResultsDietaryAndRestaurantVisit, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Find some food around here", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersDietaryAndRestaurantVisit, Limit: zep.Int(2), }, ) if err != nil { fmt.Printf("Error searching graph (DIETARY_PREFERENCE and RESTAURANT_VISIT): %v\n", err) return } if len(searchResultsDietaryAndRestaurantVisit.Edges) > 0 { for _, edge := range searchResultsDietaryAndRestaurantVisit.Edges { switch edge.Name { case "DIETARY_PREFERENCE": var dietary DietaryPreference err := zep.UnmarshalEdgeAttributes(edge.Attributes, &dietary) if err != nil { fmt.Printf("Error converting edge to DietaryPreference struct: %v\n", err) } else { fmt.Printf("Edge fact: %s\n", edge.Fact) fmt.Printf("Edge type: %s\n", edge.Name) fmt.Printf("Preference type: %s\n", dietary.PreferenceType) fmt.Printf("Allergy: %v\n", dietary.Allergy) } case "RESTAURANT_VISIT": var visit RestaurantVisit err := zep.UnmarshalEdgeAttributes(edge.Attributes, &visit) if err != nil { fmt.Printf("Error converting edge to RestaurantVisit struct: %v\n", err) } else { fmt.Printf("Edge fact: %s\n", edge.Fact) fmt.Printf("Edge type: %s\n", edge.Name) fmt.Printf("Restaurant name: %s\n", visit.RestaurantName) } default: fmt.Printf("Unknown edge type: %s\n", edge.Name) } fmt.Println() } } ``` ```text Edge fact: User John Doe is going to Green Leaf Cafe Edge type: RESTAURANT_VISIT Restaurant name: Green Leaf Cafe ``` ```text Edge fact: User states 'I'm vegetarian' indicating a dietary preference. Edge type: DIETARY_PREFERENCE Preference type: vegetarian Allergy: false ``` ### Important Notes/Tips Some notes regarding custom entity and edge types: * The `set_ontology` method overwrites any previously defined custom entity and edge types, so the set of custom entity and edge types is always the list of types provided in the last `set_ontology` method call * The overall set of entity types for a project includes both the custom entity types you set and the default entity types * There are no default edge types * You can overwrite the default entity types by providing custom entity types with the same names * Changing the custom entity or edge types will not update previously created nodes or edges. The classification and attributes of existing nodes and edges will stay the same. The only thing that can change existing classifications or attributes is adding data that provides new information. * When creating custom entity or edge types, avoid using the following attribute names (including in Go struct tags), as they conflict with default attributes: `uuid`, `name`, `group_id`, `name_embedding`, `summary`, and `created_at` * **Tip**: Design custom entity types to represent entities/nouns, and design custom edge types to represent relationships/verbs. Otherwise, your type might be represented in the graph as an edge more often than as a node or vice versa. * **Tip**: If you have overlapping entity or edge types (e.g. 'Hobby' and 'Hiking'), you can prioritize one type over another by mentioning which to prioritize in the entity or edge type descriptions # Adding Data to the Graph ## Overview Requests to add data to the same graph are completed sequentially to ensure the graph is built correctly. A large number of calls to add data to the same graph may result in lengthy processing times. In addition to incorporating memory through chat history, Zep offers the capability to add data directly to the graph. Zep supports three distinct data types: message, text, and JSON. The message type is ideal for adding data in the form of chat messages that are not directly associated with a Zep [Session's](/sessions) chat history. This encompasses any communication with a designated speaker, such as emails or previous chat logs. The text type is designed for raw text data without a specific speaker attribution. This category includes content from internal documents, wiki articles, or company handbooks. It's important to note that Zep does not process text directly from links or files. The JSON type may be used to add any JSON document to Zep. This may include REST API responses or JSON-formatted business data. The `graph.add` endpoint has a data size limit of 10,000 characters. You can add data to either a user graph by providing a `user_id`, or to a [group graph](/groups) by specifying a `group_id`. ## Adding Message Data Here's an example demonstrating how to add message data to the graph: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) message = "Paul (user): I went to Eric Clapton concert last night" new_episode = client.graph.add( user_id="user123", # Optional user ID type="message", # Specify type as "message" data=message ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const message = "User: I really enjoy working with TypeScript and React"; const newEpisode = await client.graph.add({ userId: "user123", type: "message", data: message }); ``` ## Adding Text Data Here's an example demonstrating how to add text data to the graph: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) new_episode = client.graph.add( user_id="user123", # Optional user ID type="text", # Specify type as "text" data="The user is an avid fan of Eric Clapton" ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const newEpisode = await client.graph.add({ userId: "user123", // Required: either userId or groupId type: "text", data: "The user is interested in machine learning and artificial intelligence" }); ``` ## Adding JSON Data Here's an example demonstrating how to add JSON data to the graph: ```python Python from zep_cloud.client import Zep import json client = Zep( api_key=API_KEY, ) json_data = {"name": "Eric Clapton", "age": 78, "genre": "Rock"} json_string = json.dumps(json_data) new_episode = client.graph.add( user_id=user_id, type="json", data=json_string, ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const jsonString = '{"name": "Eric Clapton", "age": 78, "genre": "Rock"}'; const newEpisode = await client.graph.add({ userId: userId, type: "json", data: jsonString, }); ``` ## Adding Custom Fact/Node Triplets You can also add manually specified fact/node triplets to the graph. You need only specify the fact, the target node name, and the source node name. Zep will then create a new corresponding edge and nodes, or use an existing edge/nodes if they exist and seem to represent the same nodes or edge you send as input. And if this new fact invalidates an existing fact, it will mark the existing fact as invalid and add the new fact triplet. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) client.graph.add_fact_triple( user_id=user_id, fact="Paul met Eric", fact_name="MET", target_node_name="Eric Clapton", source_node_name="Paul", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); await client.graph.addFactTriple({ userId: userId, fact: "Paul met Eric", factName: "MET", targetNodeName: "Eric Clapton", sourceNodeName: "Paul", }); ``` You can also specify the node summaries, edge temporal data, and UUIDs. See the [associated SDK reference](/sdk-reference/graph/add-fact-triple). ## Add Batch Data The batch add method is designed for efficiently adding a large amount of data to a user or group graph concurrently. This method is suitable when the data does not have a significant temporal dimension, such as static documents or bulk imports. Normally, data added to the graph is processed sequentially. This allows the knowledge graph to capture temporal relationships and understand when one event occurs after another. When using the batch add method, each episode is processed concurrently. As a result, temporal relationships between episodes are not captured. The batch add method is best used for static data where the order of events is not important. It is not recommended for evolving chat histories or scenarios where temporal relationships are meaningful. You can only batch up to 20 episodes at a time. You can group episodes of different types (text, json, message) in the same batch. See the [SDK reference](/sdk-reference/graph/add-batch) for details. ```python Python from zep_cloud.client import Zep from zep_cloud import EpisodeData import json client = Zep( api_key=API_KEY, ) episodes = [ EpisodeData( data="This is an example text episode.", type="text" ), EpisodeData( data=json.dumps({"name": "Eric Clapton", "age": 78, "genre": "Rock"}), type="json" ) ] client.graph.add_batch(episodes=episodes, group_id=group_id) ``` ```typescript TypeScript const episodes: EpisodeData[] = [ { data: "This is an example text episode.", type: "text" }, { data: JSON.stringify({ foo: "bar", count: 42 }), type: "json" } ]; await client.graph.addBatch({ groupId, episodes }); ``` ```go Go jsonData, _ := json.Marshal(map[string]interface{}{ "foo": "bar", "baz": 42, }) batchReq := &v2.AddDataBatchRequest{ Episodes: []*v2.EpisodeData{ { Data: "This is a text episode.", Type: v2.GraphDataTypeText, }, { Data: string(jsonData), Type: v2.GraphDataTypeJSON, }, }, GroupID: &groupID, } resp, err := client.Graph.AddBatch(context.TODO(), batchReq) if err != nil { log.Fatalf("Failed to add batch episodes: %v", err) } ``` ## Cloning Graphs The `graph.clone` method allows you to create complete copies of user or group graphs with new identifiers. This is useful for scenarios like creating test copies of user data, migrating user graphs to new identifiers, or setting up template graphs for new users. The cloning process does not copy fact ratings from the original graph. Fact ratings will not be present in the cloned graph. The target user or group must not exist - they will be created as part of the cloning operation. If no target ID is provided, one will be auto-generated and returned in the response. ### Cloning User Graphs Here's an example demonstrating how to clone a user graph: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) # Clone a user graph to a new user ID result = client.graph.clone( source_user_id="user_123", target_user_id="user_123_copy" # Optional - will be auto-generated if not provided ) print(f"Cloned graph to user: {result.user_id}") ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); // Clone a user graph to a new user ID const result = await client.graph.clone({ sourceUserId: "user_123", targetUserId: "user_123_copy" // Optional - will be auto-generated if not provided }); console.log(`Cloned graph to user: ${result.userId}`); ``` ```go Go import ( "context" "fmt" "log" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(apiKey), ) // Clone a user graph to a new user ID sourceUserID := "user_123" targetUserID := "user_123_copy" // Optional - will be auto-generated if not provided result, err := client.Graph.Clone(context.TODO(), &v2.CloneGraphRequest{ SourceUserID: &sourceUserID, TargetUserID: &targetUserID, }) if err != nil { log.Fatalf("Failed to clone graph: %v", err) } fmt.Printf("Cloned graph to user: %s\n", *result.UserID) ``` ### Cloning Group Graphs You can also clone group graphs using the same method: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) # Clone a group graph to a new group ID result = client.graph.clone( source_group_id="group_456", target_group_id="group_456_copy" # Optional - will be auto-generated if not provided ) print(f"Cloned graph to group: {result.group_id}") ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); // Clone a group graph to a new group ID const result = await client.graph.clone({ sourceGroupId: "group_456", targetGroupId: "group_456_copy" // Optional - will be auto-generated if not provided }); console.log(`Cloned graph to group: ${result.groupId}`); ``` ```go Go import ( "context" "fmt" "log" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(apiKey), ) // Clone a group graph to a new group ID sourceGroupID := "group_456" targetGroupID := "group_456_copy" // Optional - will be auto-generated if not provided result, err := client.Graph.Clone(context.TODO(), &v2.CloneGraphRequest{ SourceGroupID: &sourceGroupID, TargetGroupID: &targetGroupID, }) if err != nil { log.Fatalf("Failed to clone graph: %v", err) } fmt.Printf("Cloned graph to group: %s\n", *result.GroupID) ``` ### Key Behaviors and Limitations * **Target Requirements**: The target user or group must not exist and will be created during the cloning operation * **Auto-generation**: If no target ID is provided, Zep will auto-generate one and return it in the response * **Node Modification**: The central user entity node in the cloned graph is updated with the new user ID, and all references in the node summary are updated accordingly ## Managing Your Data on the Graph The `graph.add` method returns the [episode](/graphiti/graphiti/adding-episodes) that was created in the graph from adding that data. You can use this to maintain a mapping between your data and its corresponding episode in the graph and to delete specific data from the graph using the [delete episode](/deleting-data-from-the-graph#delete-an-episode) method. # Reading Data from the Graph Zep provides APIs to read Edges, Nodes, and Episodes from the graph. These elements can be retrieved individually using their `UUID`, or as lists associated with a specific `user_id` or `group_id`. The latter method returns all objects within the user's or group's graph. Examples of each retrieval method are provided below. ## Reading Edges ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) edge = client.graph.edge.get(edge_uuid) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const edge = client.graph.edge.get(edge_uuid); ``` ## Reading Nodes ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) node = client.graph.node.get_by_user(user_uuid) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const node = client.graph.node.get_by_user(user_uuid); ``` ## Reading Episodes ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) episode = client.graph.episode.get_by_group(group_uuid) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const episode = client.graph.episode.get_by_group(group_uuid); ``` # Searching the Graph Graph search results should be used in conjunction with [Custom Context Strings](/cookbook/customize-your-memory-context-string) to create rich, contextual prompts for AI models. Custom context strings allow you to format and structure the retrieved graph information, combining search results with conversation history and other relevant data to provide comprehensive context for your AI applications. Learn how to integrate graph search results into your context generation workflow for more effective AI interactions. ## Introduction Zep's graph search provides powerful hybrid search capabilities that combine semantic similarity with BM25 full-text search to find relevant information across your knowledge graph. This approach leverages the best of both worlds: semantic understanding for conceptual matches and full-text search for exact term matching. Additionally, you can optionally enable breadth-first search to bias results toward information connected to specific starting points in your graph. ### How It Works * **Semantic similarity**: Converts queries into embeddings to find conceptually similar content * **BM25 full-text search**: Performs traditional keyword-based search for exact matches * **Breadth-first search** (optional): Biases results toward information connected to specified starting nodes, useful for contextual relevance * **Hybrid results**: Combines and reranks results using sophisticated algorithms ### Graph Concepts * **Nodes**: Connection points representing entities (people, places, concepts) discussed in conversations or added via the Graph API * **Edges**: Relationships between nodes containing specific facts and interactions The example below demonstrates a simple search: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query=query, ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: query, }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, }) ``` Keep queries short: they are truncated at 256 characters. Long queries may increase latency without improving search quality. Break down complex searches into smaller, targeted queries. Use precise, contextual queries rather than generic ones ## Configurable Parameters Zep provides extensive configuration options to fine-tune search behavior and optimize results for your specific use case: | Parameter | Type | Description | Default | Required | | ----------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- | | `user_id` | string | Search within a specific user's graph | - | Yes\* | | `group_id` | string | Search within a group graph | - | Yes\* | | `query` | string | Search text (max 256 characters) | - | Yes | | `scope` | string | Search target: `"edges"`, `"nodes"`, or `"episodes"` | `"edges"` | No | | `reranker` | string | Reranking method: `"rrf"`, `"mmr"`, `"node_distance"`, `"episode_mentions"`, or `"cross_encoder"` | `"rrf"` | No | | `limit` | integer | Maximum number of results to return | `10` | No | | `mmr_lambda` | float | MMR diversity vs relevance balance (0.0-1.0) | - | No† | | `center_node_uuid` | string | Center node for distance-based reranking | - | No‡ | | `search_filters` | object | Filter by entity types (`node_labels`), edge types (`edge_types`), or timestamps (`created_at`, `expired_at`, `invalid_at`, `valid_at`§) | - | No | | `bfs_origin_node_uuids` | array | Node UUIDs to seed breadth-first searches from | - | No | | `min_fact_rating` | double | The minimum rating by which to filter relevant facts (range: 0.0-1.0). Can only be used when using `scope="edges"` | - | No | \*Either `user_id` OR `group_id` is required\ †Required when using `mmr` reranker\ ‡Required when using `node_distance` reranker\ §Timestamp filtering only applies to edge scope searches ## Search Scopes Zep supports three different search scopes, each optimized for different types of information retrieval: ### Edges (Default) Edges represent individual relationships and facts between entities in your graph. They contain specific interactions, conversations, and detailed information. Edge search is ideal for: * Finding specific details or conversations * Retrieving precise facts about relationships * Getting granular information about interactions ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) # Edge search (default scope) search_results = client.graph.search( user_id=user_id, query="What did John say about the project?", scope="edges", # Optional - this is the default ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); // Edge search (default scope) const searchResults = await client.graph.search({ userId: userId, query: "What did John say about the project?", scope: "edges", // Optional - this is the default }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) // Edge search (default scope) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "What did John say about the project?", Scope: zep.GraphSearchScopeEdges.Ptr(), // Optional - this is the default }) ``` ### Nodes Nodes are connection points in the graph that represent entities. Each node maintains a summary of facts from its connections (edges), providing a comprehensive overview. Node search is useful for: * Understanding broader context around entities * Getting entity summaries and overviews * Finding all information related to a specific person, place, or concept ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( group_id=group_id, query="John Smith", scope="nodes", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ groupId: groupId, query: "John Smith", scope: "nodes", }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ GroupID: zep.String(groupID), Query: "John Smith", Scope: zep.GraphSearchScopeNodes.Ptr(), }) ``` ### Episodes Episodes represent individual messages or chunks of data sent to Zep. Episode search allows you to find relevant episodes based on their content, making it ideal for: * Finding specific messages or data chunks related to your query * Discovering when certain topics were mentioned * Retrieving relevant individual interactions * Understanding the context of specific messages ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="project discussion", scope="episodes", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "project discussion", scope: "episodes", }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "project discussion", Scope: zep.GraphSearchScopeEpisodes.Ptr(), }) ``` ## Rerankers Zep provides multiple reranking algorithms to optimize search results for different use cases. Each reranker applies a different strategy to prioritize and order results: ### RRF (Reciprocal Rank Fusion) Reciprocal Rank Fusion is the default reranker that intelligently combines results from both semantic similarity and BM25 full-text search. It merges the two result sets by considering the rank position of each result in both searches, creating a unified ranking that leverages the strengths of both approaches. **When to use**: RRF is ideal for most general-purpose search scenarios where you want balanced results combining conceptual understanding with exact keyword matching. ### MMR (Maximal Marginal Relevance) Maximal Marginal Relevance addresses a common issue in similarity searches: highly similar top results that don't add diverse information to your context. MMR reranks results to balance relevance with diversity, promoting varied but still relevant results over redundant similar ones. **When to use**: Use MMR when you need diverse information for comprehensive context, such as generating summaries, answering complex questions, or avoiding repetitive results. **Required parameter**: `mmr_lambda` (0.0-1.0) - Controls the balance between relevance (1.0) and diversity (0.0). A value of 0.5 provides balanced results. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="project status", reranker="mmr", mmr_lambda=0.5, # Balance diversity vs relevance ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "project status", reranker: "mmr", mmrLambda: 0.5, // Balance diversity vs relevance }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "project status", Reranker: zep.GraphSearchQueryRerankerMmr.Ptr(), MmrLambda: zep.Float64(0.5), // Balance diversity vs relevance }) ``` ### Cross Encoder `cross_encoder` uses a specialized neural model that jointly analyzes the query and each search result together, rather than analyzing them separately. This provides more accurate relevance scoring by understanding the relationship between the query and potential results in a single model pass. **When to use**: Use cross encoder when you need the highest accuracy in relevance scoring and are willing to trade some performance for better results. Ideal for critical searches where precision is paramount. **Trade-offs**: Higher accuracy but slower performance compared to other rerankers. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="critical project decision", reranker="cross_encoder", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "critical project decision", reranker: "cross_encoder", }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "critical project decision", Reranker: zep.GraphSearchQueryRerankerCrossEncoder.Ptr(), }) ``` ### Episode Mentions `episode_mentions` reranks search results based on how frequently nodes or edges have been mentioned across all episodes, including both conversational episodes (chat history) and episodes created via `graph.add`. Results that appear more often across these episodes are prioritized, reflecting their importance and relevance. **When to use**: Use episode mentions when you want to surface information that has been frequently referenced across conversations or data uploads. Useful for understanding recurring themes, important topics, or frequently mentioned entities across all your graph data. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="team feedback", reranker="episode_mentions", ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "team feedback", reranker: "episode_mentions", }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "team feedback", Reranker: zep.GraphSearchQueryRerankerEpisodeMentions.Ptr(), }) ``` ### Node Distance `node_distance` reranks search results based on graph proximity, prioritizing results that are closer (fewer hops) to a specified center node. This spatial approach to relevance is useful for finding information contextually related to a specific entity or concept. **When to use**: Use node distance when you want to find information specifically related to a particular entity, person, or concept in your graph. Ideal for exploring the immediate context around a known entity. **Required parameter**: `center_node_uuid` - The UUID of the node to use as the center point for distance calculations. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="recent activities", reranker="node_distance", center_node_uuid=center_node_uuid, ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "recent activities", reranker: "node_distance", centerNodeUuid: centerNodeUuid, }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "recent activities", Reranker: zep.GraphSearchQueryRerankerNodeDistance.Ptr(), CenterNodeUuid: zep.String(centerNodeUuid), }) ``` ## Search Filters Zep allows you to filter search results by specific entity types or edge types, enabling more targeted searches within your graph. ### Entity Type Filtering Filter search results to only include nodes of specific entity types. This is useful when you want to focus on particular kinds of entities (e.g., only people, only companies, only locations). ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="software engineers", scope="nodes", search_filters={ "node_labels": ["Person", "Company"] } ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "software engineers", scope: "nodes", searchFilters: { nodeLabels: ["Person", "Company"] } }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchFilters := zep.SearchFilters{NodeLabels: []string{"Person", "Company"}} searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "software engineers", Scope: zep.GraphSearchScopeNodes.Ptr(), SearchFilters: &searchFilters, }) ``` ### Edge Type Filtering Filter search results to only include edges of specific relationship types. This helps you find particular kinds of relationships or interactions between entities. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) search_results = client.graph.search( user_id=user_id, query="project collaboration", scope="edges", search_filters={ "edge_types": ["WORKS_WITH", "COLLABORATES_ON"] } ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); const searchResults = await client.graph.search({ userId: userId, query: "project collaboration", scope: "edges", searchFilters: { edgeTypes: ["WORKS_WITH", "COLLABORATES_ON"] } }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) searchFilters := zep.SearchFilters{EdgeTypes: []string{"WORKS_WITH", "COLLABORATES_ON"}} searchResults, err := client.Graph.Search(context.TODO(), &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "project collaboration", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFilters, }) ``` ### Datetime Filtering Filter search results based on timestamps, enabling temporal-based queries to find information from specific time periods. This feature allows you to search for content based on four different timestamp types, each serving a distinct purpose in tracking the lifecycle of facts in your knowledge graph. Datetime filtering only applies to edge scope searches. When using `scope="nodes"` or `scope="episodes"`, datetime filter values are ignored and have no effect on search results. **Available Timestamp Types:** | Timestamp | Description | Example Use Case | | ------------ | ---------------------------------------------------- | ------------------------------------------------------ | | `created_at` | The time when Zep learned the fact was true | Finding when information was first added to the system | | `valid_at` | The real world time that the fact started being true | Identifying when a relationship or state began | | `invalid_at` | The real world time that the fact stopped being true | Finding when a relationship or state ended | | `expired_at` | The time that Zep learned that the fact was false | Tracking when information was marked as outdated | For example, for the fact "Alice is married to Bob": * `valid_at`: The time they got married * `invalid_at`: The time they got divorced * `created_at`: The time Zep learned they were married * `expired_at`: The time Zep learned they were divorced **Logic Behavior:** * **Outer array/list**: Uses OR logic - any condition group can match * **Inner array/list**: Uses AND logic - all conditions within a group must match In the example below, results are returned if they match: * (created >= 2025-07-01 AND created \< 2025-08-01) OR (created \< 2025-05-01) **Date Format**: All dates must be in ISO 8601 format with timezone (e.g., "2025-07-01T20:57:56Z") **Comparison Operators**: Supports `>=`, `<=`, `<`, and `>` for flexible date range queries ```python Python from zep_cloud.client import Zep from zep_cloud.types import SearchFilters, DateFilter client = Zep( api_key=API_KEY, ) # Search for edges created in July 2025 OR before May 2025 search_results = client.graph.search( user_id=user_id, query="project discussions", scope="edges", search_filters=SearchFilters( created_at=[ # First condition group (AND logic within) [DateFilter(comparison_operator=">=", date="2025-07-01T20:57:56Z"), DateFilter(comparison_operator="<", date="2025-08-01T20:57:56Z")], # Second condition group (OR logic with first group) [DateFilter(comparison_operator="<", date="2025-05-01T20:57:56Z")], ] ) ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); // Search for edges created in July 2025 OR before May 2025 const searchResults = await client.graph.search({ userId: userId, query: "project discussions", scope: "edges", searchFilters: { createdAt: [ // First condition group (AND logic within) [ {comparisonOperator: ">=", date: "2025-07-01T20:57:56Z"}, {comparisonOperator: "<", date: "2025-08-01T20:57:56Z"} ], // Second condition group (OR logic with first group) [ {comparisonOperator: "<", date: "2025-05-01T20:57:56Z"} ] ] } }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) // Search for edges created in July 2025 OR before May 2025 searchResults, err := client.Graph.Search(ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "project discussions", Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &zep.SearchFilters{ CreatedAt: [][]*zep.DateFilter{ // First condition group (AND logic within) { { ComparisonOperator: zep.ComparisonOperatorGreaterThanEqual, Date: "2025-07-01T20:57:56Z", }, { ComparisonOperator: zep.ComparisonOperatorLessThan, Date: "2025-08-01T20:57:56Z", }, }, // Second condition group (OR logic with first group) { { ComparisonOperator: zep.ComparisonOperatorLessThan, Date: "2025-05-01T20:57:56Z", }, }, }, }, }) ``` **Common Use Cases:** * **Date Range Filtering**: Find facts from specific time periods using any timestamp type * **Recent Activity**: Search for edges created or expired after a certain date using `>=` operator * **Historical Data**: Find older information using `<` or `<=` operators on any timestamp * **Validity Period Analysis**: Use `valid_at` and `invalid_at` together to find facts that were true during specific periods * **Audit Trail**: Use `created_at` and `expired_at` to track when your system learned about changes * **Complex Temporal Queries**: Combine multiple date conditions across different timestamp types ## Filtering by Fact Rating The `min_fact_rating` parameter allows you to filter search results based on the relevancy rating of facts stored in your graph edges. When specified, all facts returned will have at least the minimum rating value you set. This parameter accepts values between 0.0 and 1.0, where higher values indicate more relevant facts. By setting a minimum threshold, you can ensure that only highly relevant facts are included in your search results. **Important**: The `min_fact_rating` parameter can only be used when searching with `scope="edges"` as fact ratings are associated with edge relationships. Read more about [fact ratings and how they work](/facts#rating-facts-for-relevancy). ## Breadth-First Search (BFS) The `bfs_origin_node_uuids` parameter enables breadth-first searches starting from specified nodes, which helps make search results more relevant to recent context. This is particularly useful when combined with recent episode IDs to bias search results toward information connected to recent conversations. You can pass episode IDs as BFS node IDs because episodes are represented as nodes under the hood. **When to use**: Use BFS when you want to find information that's contextually connected to specific starting points in your graph, such as recent episodes or important entities. ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) # Get recent episodes to use as BFS origin points episodes = client.graph.episode.get_by_user_id( user_id=user_id, lastn=10 ).episodes episode_uuids = [episode.uuid_ for episode in episodes if episode.role_type == 'user'] # Search with BFS starting from recent episodes search_results = client.graph.search( user_id=user_id, query="project updates", scope="edges", bfs_origin_node_uuids=episode_uuids, limit=10 ) ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); // Get recent episodes to use as BFS origin points const episodeResponse = await client.graph.episode.getByUserId(userId, { lastn: 10 }); const episodeUuids = (episodeResponse.episodes || []) .filter((episode) => episode.roleType === "user") .map((episode) => episode.uuid); // Search with BFS starting from recent episodes const searchResults = await client.graph.search({ userId: userId, query: "project updates", scope: "edges", bfsOriginNodeUuids: episodeUuids, limit: 10, }); ``` ```go Go import ( "context" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" ) client := zepclient.NewClient( option.WithAPIKey(API_KEY), ) // Get recent episodes to use as BFS origin points response, err := client.Graph.Episode.GetByUserID( ctx, userID, &zep.EpisodeGetByUserIDRequest{ Lastn: zep.Int(10), }, ) var episodeUUIDs []string for _, episode := range response.Episodes { if episode.RoleType != nil && *episode.RoleType == zep.RoleTypeUserRole { episodeUUIDs = append(episodeUUIDs, episode.UUID) } } // Search with BFS starting from recent episodes searchResults, err := client.Graph.Search(ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "project updates", Scope: zep.GraphSearchScopeEdges.Ptr(), BfsOriginNodeUUIDs: episodeUUIDs, Limit: zep.Int(10), }) ``` # Deleting Data from the Graph ## Delete an Edge Here's how to delete an edge from a graph: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) client.graph.edge.delete(uuid_="your_edge_uuid") ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); await client.graph.edge.delete("your_edge_uuid"); ``` Note that when you delete an edge, it never deletes the associated nodes, even if it means there will be a node with no edges. And currently, nodes with no edges will not appear in the graph explorer, but they will still exist in the graph and be retrievable in memory. ## Delete an Episode Deleting an episode does not regenerate the names or summaries of nodes shared with other episodes. This episode information may still exist within these nodes. If an episode invalidates a fact, and the episode is deleted, the fact will remain marked as invalidated. When you delete an [episode](/graphiti/graphiti/adding-episodes), it will delete all the edges associated with it, and it will delete any nodes that are only attached to that episode. Nodes that are also attached to another episode will not be deleted. Here's how to delete an episode from a graph: ```python Python from zep_cloud.client import Zep client = Zep( api_key=API_KEY, ) client.graph.episode.delete(uuid_="episode_uuid") ``` ```typescript TypeScript import { ZepClient } from "@getzep/zep-cloud"; const client = new ZepClient({ apiKey: API_KEY, }); await client.graph.episode.delete("episode_uuid"); ``` ## Delete a Node This feature is coming soon. # Debugging > Debug workflow execution logs for graph operations Zep provides detailed debugging capabilities to help you troubleshoot and optimize your graph operations. Debug logging captures detailed workflow execution logs that can be invaluable for understanding how your data flows through the system. ## Enabling Debug Logging Debug logging is enabled from the Project Settings page in your Zep dashboard. Once enabled, debug logging will be active for 60 minutes. > **Important**: Debug logging will be active for the next 60 minutes. During this time, all workflow executions will have detailed logs captured. You can view these logs in the session logs dialog for any session that runs during this period. ## Accessing Debug Logs Debug logs are available from episode lists for both individual users and graph-wide operations. ## Viewing Debug Logs To view debug logs for a specific episode: 1. Navigate to the episode list (either from a user or graph view) 2. Find the episode you want to debug 3. Click on the **Actions** menu for that episode 4. Select **Debug Logs** This will open a detailed view of the workflow execution logs for that specific episode, showing you: * Step-by-step execution flow * Processing timestamps * Error messages and stack traces * Performance metrics * Data transformation details ## Best Practices for Debug Logging * **Enable selectively**: Only enable debug logging when actively troubleshooting to avoid unnecessary overhead * **Time-limited sessions**: Debug logging automatically disables after 60 minutes to prevent performance impact * **Review promptly**: Review debug logs within 24 hours. Stale debug logs are removed after 24 hours. # Check Data Ingestion Status Data added to Zep is processed asynchronously and can take a few seconds to a few minutes to finish processing. In this recipe, we show how to check whether a given data upload request (also known as an [Episode](/graphiti/graphiti/adding-episodes)) is finished processing by polling Zep with the `graph.episode.get` method. First, let's create a user: ```python import os import uuid import time from dotenv import find_dotenv, load_dotenv from zep_cloud.client import Zep load_dotenv(dotenv_path=find_dotenv()) client = Zep(api_key=os.environ.get("ZEP_API_KEY")) uuid_value = uuid.uuid4().hex[:4] user_id = "-" + uuid_value client.user.add( user_id=user_id, first_name = "John", last_name = "Doe", email="[email protected]" ) ``` ```typescript import { ZepClient } from "@getzep/zep-cloud"; import * as dotenv from "dotenv"; import { v4 as uuidv4 } from 'uuid'; // Load environment variables dotenv.config(); const client = new ZepClient({ apiKey: process.env.ZEP_API_KEY || "" }); const uuidValue = uuidv4().substring(0, 4); const userId = "-" + uuidValue; async function main() { // Add user await client.user.add({ userId: userId, firstName: "John", lastName: "Doe", email: "[email protected]" }); ``` ```go package main import ( "context" "fmt" "os" "strings" "time" "github.com/getzep/zep-go/v2" zepclient "github.com/getzep/zep-go/v2/client" "github.com/getzep/zep-go/v2/option" "github.com/google/uuid" "github.com/joho/godotenv" ) func main() { // Load .env file err := godotenv.Load() if err != nil { fmt.Println("Warning: Error loading .env file:", err) // Continue execution as environment variables might be set in the system } // Get API key from environment variable apiKey := os.Getenv("ZEP_API_KEY") if apiKey == "" { fmt.Println("ZEP_API_KEY environment variable is not set") return } // Initialize Zep client client := zepclient.NewClient( option.WithAPIKey(apiKey), ) // Create a UUID uuidValue := strings.ToLower(uuid.New().String()[:4]) // Create user ID userID := "-" + uuidValue // Create context ctx := context.Background() // Add a user userRequest := &zep.CreateUserRequest{ UserID: zep.String(userID), FirstName: zep.String("John"), LastName: zep.String("Doe"), Email: zep.String("[email protected]"), } _, err = client.User.Add(ctx, userRequest) if err != nil { fmt.Printf("Error creating user: %v\n", err) return } ``` Now, let's add some data and immediately try to search for that data; because data added to Zep is processed asynchronously and can take a few seconds to a few minutes to finish processing, our search results do not have the data we just added: ```python episode = client.graph.add( user_id=user_id, type="text", data="The user is an avid fan of Eric Clapton" ) search_results = client.graph.search( user_id=user_id, query="Eric Clapton", scope="nodes", limit=1, reranker="cross_encoder", ) print(search_results.nodes) ``` ```typescript // Add episode to graph const episode = await client.graph.add({ userId: userId, type: "text", data: "The user is an avid fan of Eric Clapton" }); // Search for nodes related to Eric Clapton const searchResults = await client.graph.search({ userId: userId, query: "Eric Clapton", scope: "nodes", limit: 1, reranker: "cross_encoder" }); console.log(searchResults.nodes); ``` ```go // Add a new episode to the graph episode, err := client.Graph.Add(ctx, &zep.AddDataRequest{ GroupID: zep.String(userID), Type: zep.GraphDataTypeText.Ptr(), Data: zep.String("The user is an avid fan of Eric Clapton"), }) if err != nil { fmt.Printf("Error adding episode to graph: %v\n", err) return } // Search for the data searchResults, err := client.Graph.Search(ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Eric Clapton", Scope: zep.GraphSearchScopeNodes.Ptr(), Limit: zep.Int(1), Reranker: zep.RerankerCrossEncoder.Ptr(), }) if err != nil { fmt.Printf("Error searching graph: %v\n", err) return } fmt.Println(searchResults.Nodes) ``` ```text None ``` We can check the status of the episode to see when it has finished processing, using the episode returned from the `graph.add` method and the `graph.episode.get` method: ```python while True: episode = client.graph.episode.get( uuid_=episode.uuid_, ) if episode.processed: print("Episode processed successfully") break print("Waiting for episode to process...") time.sleep(1) ``` ```typescript // Check if episode is processed const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); let processedEpisode = await client.graph.episode.get(episode.uuid); while (!processedEpisode.processed) { console.log("Waiting for episode to process..."); await sleep(1000); // Sleep for 1 second processedEpisode = await client.graph.episode.get(episode.uuid); } console.log("Episode processed successfully"); ``` ```go // Wait for the episode to be processed for { episodeStatus, err := client.Graph.Episode.Get( ctx, episode.UUID, ) if err != nil { fmt.Printf("Error getting episode: %v\n", err) return } if episodeStatus.Processed != nil && *episodeStatus.Processed { fmt.Println("Episode processed successfully") break } fmt.Println("Waiting for episode to process...") time.Sleep(1 * time.Second) } ``` ```text Waiting for episode to process... Waiting for episode to process... Waiting for episode to process... Waiting for episode to process... Waiting for episode to process... Episode processed successfully ``` Now that the episode has finished processing, we can search for the data we just added, and this time we get a result: ```python search_results = client.graph.search( user_id=user_id, query="Eric Clapton", scope="nodes", limit=1, reranker="cross_encoder", ) print(search_results.nodes) ``` ```typescript // Search again after processing const finalSearchResults = await client.graph.search({ userId: userId, query: "Eric Clapton", scope: "nodes", limit: 1, reranker: "cross_encoder" }); console.log(finalSearchResults.nodes); } // Execute the main function main().catch(error => console.error("Error:", error)); ``` ```go // Search again after processing searchResults, err = client.Graph.Search(ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: "Eric Clapton", Scope: zep.GraphSearchScopeNodes.Ptr(), Limit: zep.Int(1), Reranker: zep.RerankerCrossEncoder.Ptr(), }) if err != nil { fmt.Printf("Error searching graph: %v\n", err) return } fmt.Println(searchResults.Nodes) } ``` ```text [EntityNode(attributes={'category': 'Music', 'labels': ['Entity', 'Preference']}, created_at='2025-04-05T00:17:59.66565Z', labels=['Entity', 'Preference'], name='Eric Clapton', summary='The user is an avid fan of Eric Clapton.', uuid_='98808054-38ad-4cba-ba07-acd5f7a12bc0', graph_id='6961b53f-df05-48bb-9b8d-b2702dd72045')] ``` # Customize Your Context String When using [`graph.search`](/concepts#using-graphsearch) instead of [`memory.get`](/concepts#using-memoryget), you need to use the search results to create a custom context string. In this recipe, we will demonstrate how to build a custom memory context string using the [graph search API](/searching-the-graph). We will also use the [custom entity and edge types feature](/customizing-graph-structure#custom-entity-and-edge-types), though using this feature is optional. # Add data First, we define our [custom entity and edge types](/customizing-graph-structure#definition-1), create a user, and add some example data: ```python import uuid from zep_cloud import Message from zep_cloud.external_clients.ontology import EntityModel, EntityText, EdgeModel, EntityBoolean from zep_cloud import EntityEdgeSourceTarget from pydantic import Field class Restaurant(EntityModel): """ Represents a specific restaurant. """ cuisine_type: EntityText = Field(description="The cuisine type of the restaurant, for example: American, Mexican, Indian, etc.", default=None) dietary_accommodation: EntityText = Field(description="The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc.", default=None) class RestaurantVisit(EdgeModel): """ Represents the fact that the user visited a restaurant. """ restaurant_name: EntityText = Field(description="The name of the restaurant the user visited", default=None) class DietaryPreference(EdgeModel): """ Represents the fact that the user has a dietary preference or dietary restriction. """ preference_type: EntityText = Field(description="Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc.", default=None) allergy: EntityBoolean = Field(description="Whether this dietary preference represents a user allergy: True or false", default=None) client.graph.set_ontology( entities={ "Restaurant": Restaurant, }, edges={ "RESTAURANT_VISIT": ( RestaurantVisit, [EntityEdgeSourceTarget(source="User", target="Restaurant")] ), "DIETARY_PREFERENCE": ( DietaryPreference, [EntityEdgeSourceTarget(source="User")] ), } ) messages_session1 = [ Message(content="Take me to a lunch place", role_type="user", role="John Doe"), Message(content="How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", role_type="assistant", role="Assistant"), Message(content="Do any of those have vegetarian options? I’m vegetarian", role_type="user", role="John Doe"), Message(content="Yes, Green Leaf Cafe has vegetarian options", role_type="assistant", role="Assistant"), Message(content="Let’s go to Green Leaf Cafe", role_type="user", role="John Doe"), Message(content="Navigating to Green Leaf Cafe", role_type="assistant", role="Assistant"), ] messages_session2 = [ Message(content="Take me to dessert", role_type="user", role="John Doe"), Message(content="How about getting some ice cream?", role_type="assistant", role="Assistant"), Message(content="I can't have ice cream, I'm lactose intolerant, but I'm craving a chocolate chip cookie", role_type="user", role="John Doe"), Message(content="Sure, there's Insomnia Cookies nearby.", role_type="assistant", role="Assistant"), Message(content="Perfect, let's go to Insomnia Cookies", role_type="user", role="John Doe"), Message(content="Navigating to Insomnia Cookies.", role_type="assistant", role="Assistant"), ] user_id = f"user-{uuid.uuid4()}" client.user.add(user_id=user_id, first_name="John", last_name="Doe", email="[email protected]") session1_id = f"session-{uuid.uuid4()}" session2_id = f"session-{uuid.uuid4()}" client.memory.add_session(session_id=session1_id, user_id=user_id) client.memory.add_session(session_id=session2_id, user_id=user_id) client.memory.add(session_id=session1_id, messages=messages_session1, ignore_roles=["assistant"]) client.memory.add(session_id=session2_id, messages=messages_session2, ignore_roles=["assistant"]) ``` ```typescript import { entityFields, EntityType, EdgeType } from "@getzep/zep-cloud/wrapper/ontology"; import { v4 as uuidv4 } from "uuid"; import type { Message } from "@getzep/zep-cloud/api"; const RestaurantSchema: EntityType = { description: "Represents a specific restaurant.", fields: { cuisine_type: entityFields.text("The cuisine type of the restaurant, for example: American, Mexican, Indian, etc."), dietary_accommodation: entityFields.text("The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc."), }, }; const RestaurantVisit: EdgeType = { description: "Represents the fact that the user visited a restaurant.", fields: { restaurant_name: entityFields.text("The name of the restaurant the user visited"), }, sourceTargets: [ { source: "User", target: "Restaurant" }, ], }; const DietaryPreference: EdgeType = { description: "Represents the fact that the user has a dietary preference or dietary restriction.", fields: { preference_type: entityFields.text("Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc."), allergy: entityFields.boolean("Whether this dietary preference represents a user allergy: True or false"), }, sourceTargets: [ { source: "User" }, ], }; await client.graph.setOntology( { Restaurant: RestaurantSchema, }, { RESTAURANT_VISIT: RestaurantVisit, DIETARY_PREFERENCE: DietaryPreference, } ); const messagesSession1: Message[] = [ { content: "Take me to a lunch place", roleType: "user", role: "John Doe" }, { content: "How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", roleType: "assistant", role: "Assistant" }, { content: "Do any of those have vegetarian options? I’m vegetarian", roleType: "user", role: "John Doe" }, { content: "Yes, Green Leaf Cafe has vegetarian options", roleType: "assistant", role: "Assistant" }, { content: "Let’s go to Green Leaf Cafe", roleType: "user", role: "John Doe" }, { content: "Navigating to Green Leaf Cafe", roleType: "assistant", role: "Assistant" }, ]; const messagesSession2: Message[] = [ { content: "Take me to dessert", roleType: "user", role: "John Doe" }, { content: "How about getting some ice cream?", roleType: "assistant", role: "Assistant" }, { content: "I can't have ice cream, I'm lactose intolerant, but I'm craving a chocolate chip cookie", roleType: "user", role: "John Doe" }, { content: "Sure, there's Insomnia Cookies nearby.", roleType: "assistant", role: "Assistant" }, { content: "Perfect, let's go to Insomnia Cookies", roleType: "user", role: "John Doe" }, { content: "Navigating to Insomnia Cookies.", roleType: "assistant", role: "Assistant" }, ]; let userId = `user-${uuidv4()}`; await client.user.add({ userId, firstName: "John", lastName: "Doe", email: "[email protected]" }); const session1Id = `session-${uuidv4()}`; const session2Id = `session-${uuidv4()}`; await client.memory.addSession({ sessionId: session1Id, userId }); await client.memory.addSession({ sessionId: session2Id, userId }); await client.memory.add(session1Id, { messages: messagesSession1, ignoreRoles: ["assistant"] }); await client.memory.add(session2Id, { messages: messagesSession2, ignoreRoles: ["assistant"] }); ``` ```go import ( "github.com/getzep/zep-go/v2" "github.com/google/uuid" ) type Restaurant struct { zep.BaseEntity `name:"Restaurant" description:"Represents a specific restaurant."` CuisineType string `description:"The cuisine type of the restaurant, for example: American, Mexican, Indian, etc." json:"cuisine_type,omitempty"` DietaryAccommodation string `description:"The dietary accommodation of the restaurant, if any, for example: vegetarian, vegan, etc." json:"dietary_accommodation,omitempty"` } type RestaurantVisit struct { zep.BaseEdge `name:"RESTAURANT_VISIT" description:"Represents the fact that the user visited a restaurant."` RestaurantName string `description:"The name of the restaurant the user visited" json:"restaurant_name,omitempty"` } type DietaryPreference struct { zep.BaseEdge `name:"DIETARY_PREFERENCE" description:"Represents the fact that the user has a dietary preference or dietary restriction."` PreferenceType string `description:"Preference type of the user: anything, vegetarian, vegan, peanut allergy, etc." json:"preference_type,omitempty"` Allergy bool `description:"Whether this dietary preference represents a user allergy: True or false" json:"allergy,omitempty"` } _, err = client.Graph.SetOntology( ctx, []zep.EntityDefinition{ Restaurant{}, }, []zep.EdgeDefinitionWithSourceTargets{ { EdgeModel: RestaurantVisit{}, SourceTargets: []zep.EntityEdgeSourceTarget{ { Source: zep.String("User"), Target: zep.String("Restaurant"), }, }, }, { EdgeModel: DietaryPreference{}, SourceTargets: []zep.EntityEdgeSourceTarget{ { Source: zep.String("User"), }, }, }, }, ) if err != nil { fmt.Printf("Error setting ontology: %v\n", err) return } messagesSession1 := []zep.Message{ {Content: "Take me to a lunch place", RoleType: "user", Role: zep.String("John Doe")}, {Content: "How about Panera Bread, Chipotle, or Green Leaf Cafe, which are nearby?", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "Do any of those have vegetarian options? I'm vegetarian", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Yes, Green Leaf Cafe has vegetarian options", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "Let's go to Green Leaf Cafe", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Navigating to Green Leaf Cafe", RoleType: "assistant", Role: zep.String("Assistant")}, } messagesSession2 := []zep.Message{ {Content: "Take me to dessert", RoleType: "user", Role: zep.String("John Doe")}, {Content: "How about getting some ice cream?", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "I can't have ice cream, I'm lactose intolerant, but I'm craving a chocolate chip cookie", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Sure, there's Insomnia Cookies nearby.", RoleType: "assistant", Role: zep.String("Assistant")}, {Content: "Perfect, let's go to Insomnia Cookies", RoleType: "user", Role: zep.String("John Doe")}, {Content: "Navigating to Insomnia Cookies.", RoleType: "assistant", Role: zep.String("Assistant")}, } userID := "user-" + uuid.NewString() userReq := &zep.CreateUserRequest{ UserID: userID, FirstName: zep.String("John"), LastName: zep.String("Doe"), Email: zep.String("[email protected]"), } _, err = client.User.Add(ctx, userReq) if err != nil { fmt.Printf("Error creating user: %v\n", err) return } session1ID := "session-" + uuid.NewString() session2ID := "session-" + uuid.NewString() session1Req := &zep.CreateSessionRequest{ SessionID: session1ID, UserID: userID, } session2Req := &zep.CreateSessionRequest{ SessionID: session2ID, UserID: userID, } _, err = client.Memory.AddSession(ctx, session1Req) if err != nil { fmt.Printf("Error creating session 1: %v\n", err) return } _, err = client.Memory.AddSession(ctx, session2Req) if err != nil { fmt.Printf("Error creating session 2: %v\n", err) return } msgPtrs1 := make([]*zep.Message, len(messagesSession1)) for i := range messagesSession1 { msgPtrs1[i] = &messagesSession1[i] } addReq1 := &zep.AddMemoryRequest{ Messages: msgPtrs1, IgnoreRoles: []zep.RoleType{ zep.RoleTypeAssistantRole, }, } _, err = client.Memory.Add(ctx, session1ID, addReq1) if err != nil { fmt.Printf("Error adding messages to session 1: %v\n", err) return } msgPtrs2 := make([]*zep.Message, len(messagesSession2)) for i := range messagesSession2 { msgPtrs2[i] = &messagesSession2[i] } addReq2 := &zep.AddMemoryRequest{ Messages: msgPtrs2, IgnoreRoles: []zep.RoleType{ zep.RoleTypeAssistantRole, }, } _, err = client.Memory.Add(ctx, session2ID, addReq2) if err != nil { fmt.Printf("Error adding messages to session 2: %v\n", err) return } ``` # Example 1: Basic custom context string ## Search For a basic custom context string, we search the graph for edges and nodes relevant to our custom query string, which typically represents a user message. Note that the default [memory context string](/concepts#memory-context) returned by `memory.get` uses the past few messages as the query instead. Additionally, note that below we retrieve the past several [episodes](/graphiti/graphiti/adding-episodes) and use those episode IDs as the BFS node IDs. We use BFS here to make the search results more relevant to the user's recent history. You can read more about how BFS works in the [Breadth-First Search section](/graph/searching-the-graph#breadth-first-search-bfs) of our searching the graph documentation. These searches can be performed in parallel to reduce latency, using our [async Python client](/quickstart#initialize-the-client), TypeScript promises, or goroutines. ```python query = "Find some food around here" episodes = client.graph.episode.get_by_user_id( user_id=user_id, lastn=10 ).episodes episode_uuids = [episode.uuid_ for episode in episodes if episode.role_type == 'user'] search_results_nodes = client.graph.search( query=query, user_id=user_id, scope='nodes', reranker='cross_encoder', limit=10, bfs_origin_node_uuids=episode_uuids ) search_results_edges = client.graph.search( query=query, user_id=user_id, scope='edges', reranker='cross_encoder', limit=10, bfs_origin_node_uuids=episode_uuids ) ``` ```typescript let query = "Find some food around here"; let episodeResponse = await client.graph.episode.getByUserId(userId, { lastn: 10 }); let episodeUuids = (episodeResponse.episodes || []) .filter((episode) => episode.roleType === "user") .map((episode) => episode.uuid); const searchResultsNodes = await client.graph.search({ userId: userId, query: query, scope: "nodes", reranker: "cross_encoder", limit: 10, bfsOriginNodeUuids: episodeUuids, }); const searchResultsEdges = await client.graph.search({ userId: userId, query: query, scope: "edges", reranker: "cross_encoder", limit: 10, bfsOriginNodeUuids: episodeUuids, }); ``` ```go import ( "github.com/getzep/zep-go/v2/graph" ) query := "Find some food around here" response, err := client.Graph.Episode.GetByUserID( ctx, userID, &graph.EpisodeGetByUserIDRequest{ Lastn: zep.Int(10), }, ) if err != nil { fmt.Printf("Error getting episodes: %v\n", err) return } var episodeUUIDs1 []string for _, episode := range response.Episodes { if episode.RoleType != nil && *episode.RoleType == zep.RoleTypeUserRole { episodeUUIDs1 = append(episodeUUIDs1, episode.UUID) } } searchResultsNodes, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, Scope: zep.GraphSearchScopeNodes.Ptr(), Reranker: zep.RerankerCrossEncoder.Ptr(), Limit: zep.Int(10), BfsOriginNodeUUIDs: episodeUUIDs1, }, ) if err != nil { fmt.Printf("Error searching graph (nodes): %v\n", err) return } searchResultsEdges, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, Scope: zep.GraphSearchScopeEdges.Ptr(), Reranker: zep.RerankerCrossEncoder.Ptr(), Limit: zep.Int(10), BfsOriginNodeUUIDs: episodeUUIDs1, }, ) if err != nil { fmt.Printf("Error searching graph (edges): %v\n", err) return } ``` ## Build the context string Using the search results and a few helper functions, we can build the context string. Note that for nodes, we typically want to unpack the node name and node summary, and for edges we typically want to unpack the fact and the temporal validity information: ```python from zep_cloud import EntityEdge, EntityNode CONTEXT_STRING_TEMPLATE = """ FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) {facts} # These are the most relevant entities # ENTITY_NAME: entity summary {entities} """ def format_fact(edge: EntityEdge) -> str: valid_at = edge.valid_at if edge.valid_at is not None else "date unknown" invalid_at = edge.invalid_at if edge.invalid_at is not None else "present" formatted_fact = f" - {edge.fact} (Date range: {valid_at} - {invalid_at})" return formatted_fact def format_entity(node: EntityNode) -> str: formatted_entity = f" - {node.name}: {node.summary}" return formatted_entity def compose_context_string(edges: list[EntityEdge], nodes: list[EntityNode]) -> str: facts = [format_fact(edge) for edge in edges] entities = [format_entity(node) for node in nodes] return CONTEXT_STRING_TEMPLATE.format(facts='\n'.join(facts), entities='\n'.join(entities)) edges = search_results_edges.edges nodes = search_results_nodes.nodes context_string = compose_context_string(edges, nodes) print(context_string) ``` ```typescript import type { EntityEdge, EntityNode } from "@getzep/zep-cloud/api"; const CONTEXT_STRING_TEMPLATE_1 = `FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) {facts} # These are the most relevant entities # ENTITY_NAME: entity summary {entities} `; function formatFact(edge: EntityEdge): string { const validAt = edge.validAt ?? "date unknown"; const invalidAt = edge.invalidAt ?? "present"; return ` - ${edge.fact} (Date range: ${validAt} - ${invalidAt})`; } function formatEntity(node: EntityNode): string { return ` - ${node.name}: ${node.summary}`; } function composeContextString1(edges: EntityEdge[], nodes: EntityNode[]): string { const facts = edges.map(formatFact).join('\n'); const entities = nodes.map(formatEntity).join('\n'); return CONTEXT_STRING_TEMPLATE_1 .replace('{facts}', facts) .replace('{entities}', entities); } const edges: EntityEdge[] = searchResultsEdges.edges ?? []; const nodes: EntityNode[] = searchResultsNodes.nodes ?? []; const contextString1 = composeContextString1(edges, nodes); console.log(contextString1); ``` ```go import ( "strings" ) const CONTEXT_STRING_TEMPLATE_1 = `FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) {facts} # These are the most relevant entities # ENTITY_NAME: entity summary {entities} ` formatFact := func(edge *zep.EntityEdge) string { validAt := "date unknown" if edge.ValidAt != nil && *edge.ValidAt != "" { validAt = *edge.ValidAt } invalidAt := "present" if edge.InvalidAt != nil && *edge.InvalidAt != "" { invalidAt = *edge.InvalidAt } return fmt.Sprintf(" - %s (Date range: %s - %s)", edge.Fact, validAt, invalidAt) } formatEntity := func(node *zep.EntityNode) string { return fmt.Sprintf(" - %s: %s", node.Name, node.Summary) } composeContextString1 := func(edges []*zep.EntityEdge, nodes []*zep.EntityNode) string { var facts []string for _, edge := range edges { facts = append(facts, formatFact(edge)) } var entities []string for _, node := range nodes { entities = append(entities, formatEntity(node)) } result := strings.ReplaceAll(CONTEXT_STRING_TEMPLATE_1, "{facts}", strings.Join(facts, "\n")) result = strings.ReplaceAll(result, "{entities}", strings.Join(entities, "\n")) return result } edges := searchResultsEdges.Edges nodes := searchResultsNodes.Nodes contextString1 := composeContextString1(edges, nodes) fmt.Println(contextString1) ``` ```text FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) - User wants to go to dessert (Date range: 2025-06-16T02:17:25Z - present) - John Doe wants to go to a lunch place (Date range: 2025-06-16T02:17:25Z - present) - John Doe said 'Perfect, let's go to Insomnia Cookies' indicating he will visit Insomnia Cookies. (Date range: 2025-06-16T02:17:25Z - present) - John Doe said 'Let’s go to Green Leaf Cafe' indicating intention to visit (Date range: 2025-06-16T02:17:25Z - present) - John Doe is craving a chocolate chip cookie (Date range: 2025-06-16T02:17:25Z - present) - John Doe states that he is vegetarian. (Date range: 2025-06-16T02:17:25Z - present) - John Doe is lactose intolerant (Date range: 2025-06-16T02:17:25Z - present) # These are the most relevant entities # ENTITY_NAME: entity summary - lunch place: The entity is a lunch place, but no specific details about its cuisine or dietary accommodations are provided. - dessert: The entity 'dessert' refers to a preference related to sweet courses typically served at the end of a meal. The context indicates that the user has expressed an interest in going to a dessert place, but no specific dessert or place has been named. The entity is categorized as a Preference and Entity, but no additional attributes are provided or inferred from the messages. - Green Leaf Cafe: Green Leaf Cafe is a restaurant that offers vegetarian options, making it suitable for vegetarian diners. - user: The user is John Doe, with the email [email protected]. He has shown interest in visiting Green Leaf Cafe, which offers vegetarian options, and has also expressed a preference for lactose-free options, craving a chocolate chip cookie. The user has decided to go to Insomnia Cookies. - vegetarian: The user is interested in lunch places such as Panera Bread, Chipotle, and Green Leaf Cafe. They are specifically looking for vegetarian options at these restaurants. - chocolate chip cookie: The entity is a chocolate chip cookie, which the user desires as a snack. The user is lactose intolerant and cannot have ice cream, but is craving a chocolate chip cookie. - Insomnia Cookies: Insomnia Cookies is a restaurant that offers cookies, including chocolate chip cookies. The user is interested in a dessert and has chosen to go to Insomnia Cookies. No specific cuisine type or dietary accommodations are mentioned in the messages. - lactose intolerant: The entity is a preference indicating lactose intolerance, which is a dietary restriction that prevents the individual from consuming lactose, a sugar found in milk and dairy products. The person is specifically craving a chocolate chip cookie but cannot have ice cream due to lactose intolerance. - John Doe: The user is John Doe, with user ID user-34c7a6c1-ded6-4797-9620-8b80a5e7820f, email [email protected], and role type user. He inquired about nearby lunch options and vegetarian choices, and expressed a preference for a chocolate chip cookie due to lactose intolerance. ``` # Example 2: Utilizing custom entity and edge types ## Search For a custom context string that uses custom entity and edge types, we perform multiple searches (with our custom query string) filtering to the custom entity or edge type we want to include in the context string: As we do in [Example 1](/cookbook/customize-your-memory-context-string#search), we pass episode IDs as BFS node IDs: These searches can be performed in parallel to reduce latency, using our [async Python client](/quickstart#initialize-the-client), TypeScript promises, or goroutines. ```python query = "Find some food around here" episodes = client.graph.episode.get_by_user_id( user_id=user_id, lastn=10 ).episodes episode_uuids = [episode.uuid_ for episode in episodes if episode.role_type == 'user'] search_results_restaurant_visits = client.graph.search( query=query, user_id=user_id, scope='edges', search_filters={ "edge_types": ["RESTAURANT_VISIT"] }, reranker='cross_encoder', limit=10, bfs_origin_node_uuids=episode_uuids ) search_results_dietary_preferences = client.graph.search( query=query, user_id=user_id, scope='edges', search_filters={ "edge_types": ["DIETARY_PREFERENCE"] }, reranker='cross_encoder', limit=10, bfs_origin_node_uuids=episode_uuids ) search_results_restaurants = client.graph.search( query=query, user_id=user_id, scope='nodes', search_filters={ "node_labels": ["Restaurant"] }, reranker='cross_encoder', limit=10, bfs_origin_node_uuids=episode_uuids ) ``` ```typescript query = "Find some food around here"; episodeResponse = await client.graph.episode.getByUserId(userId, { lastn: 10 }); episodeUuids = (episodeResponse.episodes || []) .filter((episode) => episode.roleType === "user") .map((episode) => episode.uuid); const searchResultsRestaurantVisits = await client.graph.search({ query, userId: userId, scope: "edges", searchFilters: { edgeTypes: ["RESTAURANT_VISIT"] }, reranker: "cross_encoder", limit: 10, bfsOriginNodeUuids: episodeUuids, }); const searchResultsDietaryPreferences = await client.graph.search({ query, userId: userId, scope: "edges", searchFilters: { edgeTypes: ["DIETARY_PREFERENCE"] }, reranker: "cross_encoder", limit: 10, bfsOriginNodeUuids: episodeUuids, }); const searchResultsRestaurants = await client.graph.search({ query, userId: userId, scope: "nodes", searchFilters: { nodeLabels: ["Restaurant"] }, reranker: "cross_encoder", limit: 10, bfsOriginNodeUuids: episodeUuids, }); ``` ```go query = "Find some food around here" response, err = client.Graph.Episode.GetByUserID( ctx, userID, &graph.EpisodeGetByUserIDRequest{ Lastn: zep.Int(10), }, ) if err != nil { fmt.Printf("Error getting episodes: %v\n", err) return } var episodeUUIDs2 []string for _, episode := range response.Episodes { if episode.RoleType != nil && *episode.RoleType == zep.RoleTypeUserRole { episodeUUIDs2 = append(episodeUUIDs2, episode.UUID) } } searchFiltersRestaurantVisits := zep.SearchFilters{EdgeTypes: []string{"RESTAURANT_VISIT"}} searchResultsRestaurantVisits, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersRestaurantVisits, Reranker: zep.RerankerCrossEncoder.Ptr(), Limit: zep.Int(10), BfsOriginNodeUUIDs: episodeUUIDs2, }, ) if err != nil { fmt.Printf("Error searching graph (RESTAURANT_VISIT edges): %v\n", err) return } searchFiltersDietaryPreferences := zep.SearchFilters{EdgeTypes: []string{"DIETARY_PREFERENCE"}} searchResultsDietaryPreferences, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, Scope: zep.GraphSearchScopeEdges.Ptr(), SearchFilters: &searchFiltersDietaryPreferences, Reranker: zep.RerankerCrossEncoder.Ptr(), Limit: zep.Int(10), BfsOriginNodeUUIDs: episodeUUIDs2, }, ) if err != nil { fmt.Printf("Error searching graph (DIETARY_PREFERENCE edges): %v\n", err) return } searchFiltersRestaurants := zep.SearchFilters{NodeLabels: []string{"Restaurant"}} searchResultsRestaurants, err := client.Graph.Search( ctx, &zep.GraphSearchQuery{ UserID: zep.String(userID), Query: query, Scope: zep.GraphSearchScopeNodes.Ptr(), SearchFilters: &searchFiltersRestaurants, Reranker: zep.RerankerCrossEncoder.Ptr(), Limit: zep.Int(10), BfsOriginNodeUUIDs: episodeUUIDs2, }, ) if err != nil { fmt.Printf("Error searching graph (Restaurant nodes): %v\n", err) return } ``` ## Build the context string Using the search results and a few helper functions, we can compose the context string. Note that in this example, we focus on unpacking the custom attributes of the nodes and edges, but this is a design choice that you can experiment with for your use case. Note also that we designed the context string template around the custom entity and edge types that we are unpacking into the context string: ```python from zep_cloud import EntityEdge, EntityNode CONTEXT_STRING_TEMPLATE = """ PREVIOUS_RESTAURANT_VISITS, DIETARY_PREFERENCES, and RESTAURANTS represent relevant context to the current conversation. # These are the most relevant restaurants the user has previously visited # format: restaurant_name: RESTAURANT_NAME {restaurant_visits} # These are the most relevant dietary preferences of the user, whether they represent an allergy, and their valid date ranges # format: allergy: True/False; preference_type: PREFERENCE_TYPE (Date range: from - to) {dietary_preferences} # These are the most relevant restaurants the user has discussed previously # format: name: RESTAURANT_NAME; cuisine_type: CUISINE_TYPE; dietary_accommodation: DIETARY_ACCOMMODATION {restaurants} """ def format_edge_with_attributes(edge: EntityEdge, include_timestamps: bool = True) -> str: attrs_str = '; '.join(f"{k}: {v}" for k, v in sorted(edge.attributes.items())) if include_timestamps: valid_at = edge.valid_at if edge.valid_at is not None else "date unknown" invalid_at = edge.invalid_at if edge.invalid_at is not None else "present" return f" - {attrs_str} (Date range: {valid_at} - {invalid_at})" return f" - {attrs_str}" def format_node_with_attributes(node: EntityNode) -> str: attributes = {k: v for k, v in node.attributes.items() if k != "labels"} attrs_str = '; '.join(f"{k}: {v}" for k, v in sorted(attributes.items())) base = f" - name: {node.name}; {attrs_str}" return base def compose_context_string(restaurant_visit_edges: list[EntityEdge], dietary_preference_edges: list[EntityEdge], restaurant_nodes: list[EntityNode]) -> str: restaurant_visits = [format_edge_with_attributes(edge, include_timestamps=False) for edge in restaurant_visit_edges] dietary_preferences = [format_edge_with_attributes(edge, include_timestamps=True) for edge in dietary_preference_edges] restaurant_nodes = [format_node_with_attributes(node) for node in restaurant_nodes] return CONTEXT_STRING_TEMPLATE.format(restaurant_visits='\n'.join(restaurant_visits), dietary_preferences='\n'.join(dietary_preferences), restaurants='\n'.join(restaurant_nodes)) restaurant_visit_edges = search_results_restaurant_visits.edges dietary_preference_edges = search_results_dietary_preferences.edges restaurant_nodes = search_results_restaurants.nodes context_string = compose_context_string(restaurant_visit_edges, dietary_preference_edges, restaurant_nodes) print(context_string) ``` ```typescript import type { EntityEdge, EntityNode } from "@getzep/zep-cloud/api"; const CONTEXT_STRING_TEMPLATE_2 = `PREVIOUS_RESTAURANT_VISITS, DIETARY_PREFERENCES, and RESTAURANTS represent relevant context to the current conversation. # These are the most relevant restaurants the user has previously visited # format: restaurant_name: RESTAURANT_NAME {restaurant_visits} # These are the most relevant dietary preferences of the user, whether they represent an allergy, and their valid date ranges # format: allergy: True/False; preference_type: PREFERENCE_TYPE (Date range: from - to) {dietary_preferences} # These are the most relevant restaurants the user has discussed previously # format: name: RESTAURANT_NAME; cuisine_type: CUISINE_TYPE; dietary_accommodation: DIETARY_ACCOMMODATION {restaurants} `; function formatEdgeWithAttributes(edge: EntityEdge, includeTimestamps = true): string { const attrs = Object.entries(edge.attributes ?? {}) .sort(([a], [b]) => a.localeCompare(b)) .map(([k, v]) => `${k}: ${v}`) .join('; '); if (includeTimestamps) { const validAt = edge.validAt ?? "date unknown"; const invalidAt = edge.invalidAt ?? "present"; return ` - ${attrs} (Date range: ${validAt} - ${invalidAt})`; } return ` - ${attrs}`; } function formatNodeWithAttributes(node: EntityNode): string { const attributes = Object.entries(node.attributes ?? {}) .filter(([k]) => k !== "labels") .sort(([a], [b]) => a.localeCompare(b)) .map(([k, v]) => `${k}: ${v}`) .join('; '); return ` - name: ${node.name}; ${attributes}`; } function composeContextString2( restaurantVisitEdges: EntityEdge[], dietaryPreferenceEdges: EntityEdge[], restaurantNodes: EntityNode[] ): string { const restaurantVisits = restaurantVisitEdges.map(e => formatEdgeWithAttributes(e, false)).join('\n'); const dietaryPreferences = dietaryPreferenceEdges.map(e => formatEdgeWithAttributes(e, true)).join('\n'); const restaurants = restaurantNodes.map(n => formatNodeWithAttributes(n)).join('\n'); return CONTEXT_STRING_TEMPLATE_2 .replace('{restaurant_visits}', restaurantVisits) .replace('{dietary_preferences}', dietaryPreferences) .replace('{restaurants}', restaurants); } const restaurantVisitEdges: EntityEdge[] = searchResultsRestaurantVisits.edges ?? []; const dietaryPreferenceEdges: EntityEdge[] = searchResultsDietaryPreferences.edges ?? []; const restaurantNodes: EntityNode[] = searchResultsRestaurants.nodes ?? []; const contextString2 = composeContextString2(restaurantVisitEdges, dietaryPreferenceEdges, restaurantNodes); console.log(contextString2); ``` ```go import ( "strings" ) const CONTEXT_STRING_TEMPLATE_2 = `PREVIOUS_RESTAURANT_VISITS, DIETARY_PREFERENCES, and RESTAURANTS represent relevant context to the current conversation. # These are the most relevant restaurants the user has previously visited # format: restaurant_name: RESTAURANT_NAME {restaurant_visits} # These are the most relevant dietary preferences of the user, whether they represent an allergy, and their valid date ranges # format: allergy: True/False; preference_type: PREFERENCE_TYPE (Date range: from - to) {dietary_preferences} # These are the most relevant restaurants the user has discussed previously # format: name: RESTAURANT_NAME; cuisine_type: CUISINE_TYPE; dietary_accommodation: DIETARY_ACCOMMODATION {restaurants} ` formatEdgeWithAttributes := func(edge *zep.EntityEdge, includeTimestamps bool) string { attrs := make([]string, 0) for _, k := range []string{"allergy", "preference_type", "restaurant_name"} { if v, ok := edge.Attributes[k]; ok { attrs = append(attrs, fmt.Sprintf("%s: %v", k, v)) } } attrsStr := strings.Join(attrs, "; ") if includeTimestamps { validAt := "date unknown" if edge.ValidAt != nil && *edge.ValidAt != "" { validAt = *edge.ValidAt } invalidAt := "present" if edge.InvalidAt != nil && *edge.InvalidAt != "" { invalidAt = *edge.InvalidAt } return fmt.Sprintf(" - %s (Date range: %s - %s)", attrsStr, validAt, invalidAt) } return fmt.Sprintf(" - %s", attrsStr) } formatNodeWithAttributes := func(node *zep.EntityNode) string { attrs := make([]string, 0) for k, v := range node.Attributes { if k == "labels" { continue } attrs = append(attrs, fmt.Sprintf("%s: %v", k, v)) } attrsStr := strings.Join(attrs, "; ") return fmt.Sprintf(" - name: %s; %s", node.Name, attrsStr) } composeContextString2 := func(restaurantVisitEdges []*zep.EntityEdge, dietaryPreferenceEdges []*zep.EntityEdge, restaurantNodes []*zep.EntityNode) string { restaurantVisits := make([]string, 0) for _, edge := range restaurantVisitEdges { restaurantVisits = append(restaurantVisits, formatEdgeWithAttributes(edge, false)) } dietaryPreferences := make([]string, 0) for _, edge := range dietaryPreferenceEdges { dietaryPreferences = append(dietaryPreferences, formatEdgeWithAttributes(edge, true)) } restaurants := make([]string, 0) for _, node := range restaurantNodes { restaurants = append(restaurants, formatNodeWithAttributes(node)) } result := strings.ReplaceAll(CONTEXT_STRING_TEMPLATE_2, "{restaurant_visits}", strings.Join(restaurantVisits, "\n")) result = strings.ReplaceAll(result, "{dietary_preferences}", strings.Join(dietaryPreferences, "\n")) result = strings.ReplaceAll(result, "{restaurants}", strings.Join(restaurants, "\n")) return result } restaurantVisitEdges := searchResultsRestaurantVisits.Edges dietaryPreferenceEdges := searchResultsDietaryPreferences.Edges restaurantNodes := searchResultsRestaurants.Nodes contextString2 := composeContextString2(restaurantVisitEdges, dietaryPreferenceEdges, restaurantNodes) fmt.Println(contextString2) ``` ```text PREVIOUS_RESTAURANT_VISITS, DIETARY_PREFERENCES, and RESTAURANTS represent relevant context to the current conversation. # These are the most relevant restaurants the user has previously visited # format: restaurant_name: RESTAURANT_NAME - restaurant_name: Insomnia Cookies - restaurant_name: Green Leaf Cafe # These are the most relevant dietary preferences of the user, whether they represent an allergy, and their valid date ranges # format: allergy: True/False; preference_type: PREFERENCE_TYPE (Date range: from - to) - allergy: False; preference_type: vegetarian (Date range: 2025-06-16T02:17:25Z - present) - allergy: False; preference_type: lactose intolerance (Date range: 2025-06-16T02:17:25Z - present) # These are the most relevant restaurants the user has discussed previously # format: name: RESTAURANT_NAME; cuisine_type: CUISINE_TYPE; dietary_accommodation: DIETARY_ACCOMMODATION - name: Green Leaf Cafe; dietary_accommodation: vegetarian - name: Insomnia Cookies; ``` # Add User Specific Business Data to User Graphs This guide demonstrates how to add user-specific business data to a user's knowledge graph. We'll create a user, fetch their business data, and add it to their graph. First, we will initialize our client and create a new user: ```python # Initialize the Zep client zep_client = AsyncZep(api_key=API_KEY) # Add one example user user_id_zep = uuid.uuid4().hex await zep_client.user.add( user_id=user_id_zep, email="[email protected]" ) ``` Then, we will fetch and format the user's business data. Note that the functionality to fetch a users business data will depend on your codebase. Also note that you could make your Zep user IDs equal to whatever internal user IDs you use to make things easier to manage. Generally, Zep user IDs, session IDs, Group IDs, etc. can be arbitrary strings, and can map to your app's data schema. ```python # Define the function to fetch user business data async def get_user_business_data(user_id_business): # This function returns JSON data for the given user # This would vary based on your codebase return {} # Placeholder for business user id user_id_business = "placeholder_user_id" # This would vary based on your codebase # Retrieve the user-specific business data user_data_json = await get_user_business_data(user_id_business) # Convert the business data to a string json_string = json.dumps(user_data_json) ``` Lastly, we will add the formatted data to the user's graph using the [graph API](/adding-data-to-the-graph): ```python # Add the JSON data to the user's graph await zep_client.graph.add( user_id=user_id_zep, type="json", data=json_string, ) ``` Here, we use `type="json"`, but the graph API also supports `type="text"` and `type="message"`. The `type="text"` option is useful for adding background information that is in unstructured text such as internal documents or web copy. The `type="message"` option is useful for adding data that is in a message format but is not your user's chat history, such as emails. [Read more about this here](/adding-data-to-the-graph). Also, note that when adding data to the graph, you should consider the size of the data you are adding and our payload limits. [Read more about this here](/docs/performance/performance-best-practices#optimizing-memory-operations). You have now successfully added user-specific business data to a user's knowledge graph, which can be used alongside chat history to create comprehensive user memory. # Share Memory Across Users Using Group Graphs In this recipe, we will demonstrate how to share memory across different users by utilizing group graphs. We will set up a user session, add group-specific data, and integrate the OpenAI client to show how to use both user and group memory to enhance the context of a chatbot. First, we initialize the Zep client, create a user, and create a session: ```python # Initialize the Zep client zep_client = AsyncZep(api_key="YOUR_API_KEY") # Ensure your API key is set appropriately # Add one example user user_id = uuid.uuid4().hex await zep_client.user.add( user_id=user_id, email="[email protected]" ) # Create a new session for the user session_id = uuid.uuid4().hex await zep_client.memory.add_session( session_id=session_id, user_id=user_id, ) ``` Next, we create a new group and add structured business data to the graph, in the form of a JSON string. This step uses the [groups API](/groups) and the [graph API](/adding-data-to-the-graph): ```python group_id = uuid.uuid4().hex await zep_client.group.add(group_id=group_id) product_json_data = [ { "type": "Sedan", "gas_mileage": "25 mpg", "maker": "Toyota" }, # ... more cars ] json_string = json.dumps(product_json_data) await zep_client.graph.add( group_id=group_id, type="json", data=json_string, ) ``` Finally, we initialize the OpenAI client and define a `chatbot_response` function that retrieves user and group memory, constructs a system/developer message, and generates a contextual response. This leverages the [memory API](/concepts#using-memoryget), [graph API](/searching-the-graph), and the OpenAI chat completions endpoint. ```python # Initialize the OpenAI client oai_client = OpenAI() async def chatbot_response(user_message, session_id): # Retrieve user memory user_memory = await zep_client.memory.get(session_id) # Search the group graph using the user message as the query results = await zep_client.graph.search(group_id=group_id, query=user_message, scope="edges") relevant_group_edges = results.edges product_context_string = "Below are some facts related to our car inventory that may help you respond to the user: \n" for edge in relevant_group_edges: product_context_string += f"{edge.fact}\n" # Combine context strings for the developer message developer_message = f"You are a helpful chat bot assistant for a car sales company. Answer the user's message while taking into account the following background information:\n{user_memory.context}\n{product_context_string}" # Generate a response using the OpenAI API completion = oai_client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "developer", "content": developer_message}, {"role": "user", "content": user_message} ] ) response = completion.choices[0].message # Add the conversation to memory messages = [ Message(role="user", role_type="user", content=user_message), Message(role="assistant", role_type="assistant", content=response) ] await zep_client.memory.add(session_id, messages=messages) return response ``` This recipe demonstrated how to share memory across users by utilizing group graphs with Zep. We set up user sessions, added structured group data, and integrated the OpenAI client to generate contextual responses, providing a robust approach to memory sharing across different users. # Get Most Relevant Facts for an Arbitrary Query In this recipe, we demonstrate how to retrieve the most relevant facts from the knowledge graph using an arbitrary search query. First, we perform a [search](/searching-the-graph) on the knowledge graph using a sample query: ```python zep_client = AsyncZep(api_key=API_KEY) results = await client.graph.search(user_id="some user_id", query="Some search query", scope="edges") ``` Then, we get the edges from the search results and construct our fact list. We also include the temporal validity data to each fact string: ```python # Build list of formatted facts relevant_edges = results.edges formatted_facts = [] for edge in relevant_edges: valid_at = edge.valid_at if edge.valid_at is not None else "date unknown" invalid_at = edge.invalid_at if edge.invalid_at is not None else "present" formatted_fact = f"{edge.fact} (Date range: {valid_at} - {invalid_at})" formatted_facts.append(formatted_fact) # Print the results print("\nFound facts:") for fact in formatted_facts: print(f"- {fact}") ``` We demonstrated how to retrieve the most relevant facts for an arbitrary query using the Zep client. Adjust the query and parameters as needed to tailor the search for your specific use case. # Find Facts Relevant to a Specific Node Below, we will go through how to retrieve facts which are related to a specific node in a Zep knowledge graph. First, we will go through some methods for determining the UUID of the node you are interested in. Then, we will go through some methods for retrieving the facts related to that node. If you are interested in the user's node specifically, we have a convenience method that [returns the user's node](/users#get-the-user-node) which includes the UUID. An easy way to determine the UUID for other nodes is to use the graph explorer in the [Zep Web app](https://app.getzep.com/). You can also programmatically retrieve all the nodes for a given user using our [get nodes by user API](/sdk-reference/graph/node/get-by-user-id), and then manually examine the nodes and take note of the UUID of the node of interest: ```python # Initialize the Zep client zep_client = AsyncZep(api_key=API_KEY) nodes = await zep_client.graph.node.get_by_user_id(user_id="some user ID") print(nodes) ``` ```python center_node_uuid = "your chosen center node UUID" ``` Lastly, if your user has a lot of nodes to look through, you can narrow down the search by only looking at the nodes relevant to a specific query, using our [graph search API](/searching-the-graph): ```python results = await zep_client.graph.search( user_id="some user ID", query="shoe", # To help narrow down the nodes you have to manually search scope="nodes" ) relevant_nodes = results.nodes print(relevant_nodes) ``` ```python center_node_uuid = "your chosen center node UUID" ``` The most straightforward way to get facts related to your node is to retrieve all facts that are connected to your chosen node using the [get edges by user API](/sdk-reference/graph/edge/get-by-user-id): ```python edges = await zep_client.graph.edge.get_by_user_id(user_id="some user ID") connected_edges = [edge for edge in edges if edge.source_node_uuid == center_node_uuid or edge.target_node_uuid == center_node_uuid] relevant_facts = [edge.fact for edge in connected_edges] ``` You can also retrieve facts relevant to your node by using the [graph search API](/searching-the-graph) with the node distance re-ranker: ```python results = await zep_client.graph.search( user_id="some user ID", query="some query", reranker="node_distance", center_node_uuid=center_node_uuid, ) relevant_edges = results.edges relevant_facts = [edge.fact for edge in relevant_edges] ``` In this recipe, we went through how to retrieve facts which are related to a specific node in a Zep knowledge graph. We first went through some methods for determining the UUID of the node you are interested in. Then, we went through some methods for retrieving the facts related to that node. # Performance Optimization Guide > Best practices for optimizing Zep performance in production This guide covers best practices for optimizing Zep's performance in production environments. ## Reuse the Zep SDK Client The Zep SDK client maintains an HTTP connection pool that enables connection reuse, significantly reducing latency by avoiding the overhead of establishing new connections. To optimize performance: * Create a single client instance and reuse it across your application * Avoid creating new client instances for each request or function * Consider implementing a client singleton pattern in your application * For serverless environments, initialize the client outside the handler function ## Optimizing Memory Operations The `memory.add` and `memory.get` methods are optimized for conversational messages and low-latency retrieval. For optimal performance: * Keep individual messages under 10K characters * Use `graph.add` for larger documents, tool outputs, or business data * Consider chunking large documents before adding them to the graph (the `graph.add` endpoint has a 10,000 character limit) * Remove unnecessary metadata or content before persistence * For bulk document ingestion, process documents in parallel while respecting rate limits ```python # Recommended for conversations zep_client.memory.add( session_id="session_123", message={ "role": "human", "content": "What's the weather like today?" } ) # Recommended for large documents await zep_client.graph.add( data=document_content, # Your chunked document content user_id=user_id, # Or group_id for group graphs type="text" # Can be "text", "message", or "json" ) ``` ### Get the memory context string sooner Additionally, you can request the memory context directly in the response to the `memory.add()` call. This optimization eliminates the need for a separate `memory.get()` if you happen to only need the context. Read more about [Memory Context](/concepts/#memory-context). In this scenario you can pass in the `return_context=True` flag to the `memory.add()` method. Zep will perform a user graph search right after persisting the memory and return the context relevant to the recently added memory. ```python Python memory_response = await zep_client.memory.add( session_id=session_id, messages=messages, return_context=True ) context = memory_response.context ``` ```typescript TypeScript const memoryResponse = await zepClient.memory.add(sessionId, { messages: messages, returnContext: true }); const context = memoryResponse.context; ``` ```go Go memoryResponse, err := zepClient.Memory.Add( context.TODO(), sessionID, &zep.AddMemoryRequest{ Messages: messages, ReturnContext: zep.Bool(true), }, ) if err != nil { // handle error } memoryContext := memoryResponse.Context ``` Read more in the [Memory SDK Reference](/sdk-reference/memory#add) ## Optimizing Search Queries Zep uses hybrid search combining semantic similarity and BM25 full-text search. For optimal performance: * Keep your queries concise. Queries are automatically truncated to 8,192 tokens (approximately 32,000 Latin characters) * Longer queries may not improve search quality and will increase latency * Consider breaking down complex searches into smaller, focused queries * Use specific, contextual queries rather than generic ones Best practices for search: * Keep search queries concise and specific * Structure queries to target relevant information * Use natural language queries for better semantic matching * Consider the scope of your search (user vs group graphs) ```python # Recommended - concise query results = await zep_client.graph.search( user_id=user_id, # Or group_id for group graphs query="project requirements discussion" ) # Not recommended - overly long query results = await zep_client.graph.search( user_id=user_id, query="very long text with multiple paragraphs..." # Will be truncated ) ``` ## Summary * Reuse Zep SDK client instances to optimize connection management * Use appropriate methods for different types of content (`memory.add` for conversations, `graph.add` for large documents) * Keep search queries focused and under the token limit for optimal performance # Adding JSON Best Practices > Best practices for preparing JSON data for ingestion into Zep Adding JSON to Zep without adequate preparation can lead to unexpected results. For instance, adding a large JSON without dividing it up can lead to a graph with very few nodes. Below, we go over what type of JSON works best with Zep, and techniques you can use to ensure your JSON fits these criteria. ## Key Criteria At a high level, ingestion of JSON into Zep works best when these criteria are met: 1. **JSON is not too large**: Large JSON should be divided into pieces, adding each piece separately to Zep. 2. **JSON is not deeply nested**: Deeply nested JSON (more than 3 to 4 levels) should be flattened while preserving information. 3. **JSON is understandable in isolation**: The JSON should include all the information needed to understand the data it represents. This might mean adding descriptions or understandable attribute names where relevant. 4. **JSON represents a unified entity**: The JSON should ideally represent a unified entity, with ID, name, and description fields. Zep treats the JSON as a whole as a "first class entity", creating branching entities off of the main JSON entity from the JSON's attributes. ## JSON that is too large ### JSON with too many attributes **Recommendation**: Split up the properties among several instances of the object. Each instance should duplicate the `id`, `name`, and `description` fields, or similar fields that tie each chunk to the same object, and then have 3 to 4 additional properties. ### JSON with too many list elements **Recommendation**: Split up the list into its elements, ensuring you add additional fields to contextualize each element if needed. For instance, if the key of the list is "cars", then you should add a field which indicates that the list item is a car. ### JSON with large strings **Recommendation**: A very long string might be better added to the graph as unstructured text instead of JSON. You may need to add a sentence or two to contextualize the unstructured text with respect to the rest of the JSON, since they would be added separately. And if it is very long, you would want to employ document chunking methods, such as described by Anthropic [here](https://www.anthropic.com/news/contextual-retrieval). ## JSON that is deeply nested **Recommendation**: For each deeply nested value In the JSON, create a flattened JSON piece for that value specifically. For instance, if your JSON alternates between dictionaries and lists for 5 to 6 levels with a single value at the bottom, then the flattened version would have an attribute for the value, and an attribute to convey any information from each of the keys from the original JSON. ## JSON that is not understandable in isolation **Recommendation**: Add descriptions or helpful/interpretable attribute names where relevant. ## JSON that is not a unified entity **Recommendation**: Add an `id`, `name`, and `description` field to the JSON. Additionally, if the JSON essentially represents two or more objects, split it up. ## Dealing with a combination of the above **Recommendation**: First, deal with the fact that the JSON is too large and/or too deeply nested by iteratively applying these recommendations (described above) from the top down: splitting up attributes, splitting up lists, flattening deeply nested JSON, splitting out any large text documents. For example, if your JSON has a lot of attributes and one of those attributes is a long list, then you should first split up the JSON by the attributes, and then split up the JSON piece that contains the long list by splitting the list elements. After applying the iterative transformations, you should have a list of candidate JSON, each of which is not too large or too deeply nested. As the last step, you should ensure that each JSON in the list is understandable in isolation and represents a unified entity by applying the recommendations above. # LangGraph Memory Example > LangGraph is a library created by LangChain for building stateful, multi-agent applications. This example demonstrates using Zep for LangGraph agent memory. A complete Notebook example of using Zep for LangGraph Memory may be found in the [Zep Python SDK Repository](https://github.com/getzep/zep-python/blob/main/examples/langgraph-agent/agent.ipynb). The following example demonstrates building an agent using LangGraph. Zep is used to personalize agent responses based on information learned from prior conversations. The agent implements: * persistance of new chat turns to Zep and recall of relevant Facts using the most recent messages. * an in-memory MemorySaver to maintain agent state. We use this to add recent chat history to the agent prompt. As an alternative, you could use Zep for this. You should consider truncating MemorySaver's chat history as by default LangGraph state grows unbounded. We've included this in our example below. See the LangGraph documentation for insight. ## Install dependencies ```shell pip install zep-cloud langchain-openai langgraph ipywidgets ``` ## Configure Zep Ensure that you've configured the following API key in your environment. We're using Zep's Async client here, but we could also use the non-async equivalent. ```bash ZEP_API_KEY= ``` ```python from zep_cloud.client import AsyncZep from zep_cloud import Message zep = AsyncZep(api_key=os.environ.get('ZEP_API_KEY')) ``` ```python from langchain_core.messages import AIMessage, SystemMessage, trim_messages from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import END, START, StateGraph, add_messages from langgraph.prebuilt import ToolNode ``` ## Using Zep's Search as a Tool These are examples of simple Tools that search Zep for facts (from edges) or nodes. ```python class State(TypedDict): messages: Annotated[list, add_messages] first_name: str last_name: str session_id: str user_name: str @tool async def search_facts(state: State, query: str, limit: int = 5) -> list[str]: """Search for facts in all conversations had with a user. Args: state (State): The Agent's state. query (str): The search query. limit (int): The number of results to return. Defaults to 5. Returns: list: A list of facts that match the search query. """ edges = await zep.graph.search( user_id=state["user_name"], text=query, limit=limit, search_scope="edges" ) return [edge.fact for edge in edges] @tool async def search_nodes(state: State, query: str, limit: int = 5) -> list[str]: """Search for nodes in all conversations had with a user. Args: state (State): The Agent's state. query (str): The search query. limit (int): The number of results to return. Defaults to 5. Returns: list: A list of node summaries for nodes that match the search query. """ nodes = await zep.graph.search( user_id=state["user_name"], text=query, limit=limit, search_scope="nodes" ) return [node.summary for node in nodes] tools = [search_facts, search_nodes] tool_node = ToolNode(tools) llm = ChatOpenAI(model="gpt-4o-mini", temperature=0).bind_tools(tools) ``` ## Chatbot Function Explanation The chatbot uses Zep to provide context-aware responses. Here's how it works: 1. **Context Retrieval**: It retrieves relevant facts for the user's current conversation (session). Zep uses the most recent messages to determine what facts to retrieve. 2. **System Message**: It constructs a system message incorporating the facts retrieved in 1., setting the context for the AI's response. 3. **Message Persistence**: After generating a response, it asynchronously adds the user and assistant messages to Zep. New Facts are created and existing Facts updated using this new information. 4. **Messages in State**: We use LangGraph state to store the most recent messages and add these to the Agent prompt. We limit the message list to the most recent 3 messages for demonstration purposes. We could also use Zep to recall the chat history, rather than LangGraph's MemorySaver. See [`memory.get`](/sdk-reference/memory/get) in the Zep SDK documentation. ```python async def chatbot(state: State): memory = await zep.memory.get(state["session_id"]) system_message = SystemMessage( content=f"""You are a compassionate mental health bot and caregiver. Review information about the user and their prior conversation below and respond accordingly. Keep responses empathetic and supportive. And remember, always prioritize the user's well-being and mental health. {memory.context}""" ) messages = [system_message] + state["messages"] response = await llm.ainvoke(messages) # Add the new chat turn to the Zep graph messages_to_save = [ Message( role_type="user", role=state["first_name"] + " " + state["last_name"], content=state["messages"][-1].content, ), Message(role_type="assistant", content=response.content), ] await zep.memory.add( session_id=state["session_id"], messages=messages_to_save, ) # Truncate the chat history to keep the state from growing unbounded # In this example, we going to keep the state small for demonstration purposes # We'll use Zep's Facts to maintain conversation context state["messages"] = trim_messages( state["messages"], strategy="last", token_counter=len, max_tokens=3, start_on="human", end_on=("human", "tool"), include_system=True, ) logger.info(f"Messages in state: {state['messages']}") return {"messages": [response]} ``` ## Setting up the Agent This section sets up the Agent's LangGraph graph: 1. **Graph Structure**: It defines a graph with nodes for the agent (chatbot) and tools, connected in a loop. 2. **Conditional Logic**: The `should_continue` function determines whether to end the graph execution or continue to the tools node based on the presence of tool calls. 3. **Memory Management**: It uses a MemorySaver to maintain conversation state across turns. This is in addition to using Zep for facts. ```python graph_builder = StateGraph(State) memory = MemorySaver() # Define the function that determines whether to continue or not async def should_continue(state, config): messages = state["messages"] last_message = messages[-1] # If there is no function call, then we finish if not last_message.tool_calls: return "end" # Otherwise if there is, we continue else: return "continue" graph_builder.add_node("agent", chatbot) graph_builder.add_node("tools", tool_node) graph_builder.add_edge(START, "agent") graph_builder.add_conditional_edges("agent", should_continue, {"continue": "tools", "end": END}) graph_builder.add_edge("tools", "agent") graph = graph_builder.compile(checkpointer=memory) ``` Our LangGraph agent graph is illustrated below. ![Agent Graph](file:8e1d2601-303a-4ddc-9d3e-6ff056b05b06) ## Running the Agent We generate a unique user name and thread id (session id) and add these to Zep, associating the Session with the new User. ```python first_name = "Daniel" last_name = "Chalef" user_name = first_name + uuid.uuid4().hex[:4] thread_id = uuid.uuid4().hex await zep.user.add(user_id=user_name, first_name=first_name, last_name=last_name) await zep.memory.add_session(session_id=thread_id, user_id=user_name) def extract_messages(result): output = "" for message in result["messages"]: if isinstance(message, AIMessage): role = "assistant" else: role = result["user_name"] output += f"{role}: {message.content}\n" return output.strip() async def graph_invoke( message: str, first_name: str, last_name: str, thread_id: str, ai_response_only: bool = True, ): r = await graph.ainvoke( { "messages": [ { "role": "user", "content": message, } ], "first_name": first_name, "last_name": last_name, "session_id": thread_id, }, config={"configurable": {"thread_id": thread_id}}, ) if ai_response_only: return r["messages"][-1].content else: return extract_messages(r) ``` Let's test the agent with a few messages: ```python r = await graph_invoke( "Hi there?", first_name, last_name, thread_id, ) print(r) ``` > Hello! How are you feeling today? I'm here to listen and support you. ```python r = await graph_invoke( """ I'm fine. But have been a bit stressful lately. Mostly work related. But also my dog. I'm worried about her. """, first_name, last_name, thread_id, ) print(r) ``` > I'm sorry to hear that you've been feeling stressed. Work can be a significant source of pressure, and it sounds like your dog might be adding to that stress as well. If you feel comfortable sharing, what specifically has been causing you stress at work and with your dog? I'm here to help you through it. ## Viewing The Context Value ```python memory = await zep.memory.get(session_id=thread_id) print(memory.context) ``` The context value will look something like this: ```text FACTS and ENTITIES represent relevant context to the current conversation. # These are the most relevant facts and their valid date ranges # format: FACT (Date range: from - to) - Daniel99db is worried about his sick dog. (2025-01-24 02:11:54 - present) - Daniel Chalef is worried about his sick dog. (2025-01-24 02:11:54 - present) - The assistant asks how the user is feeling. (2025-01-24 02:11:51 - present) - Daniel99db has been a bit stressful lately due to his dog. (2025-01-24 02:11:53 - present) - Daniel99db has been a bit stressful lately due to work. (2025-01-24 02:11:53 - present) - Daniel99db is a user. (2025-01-24 02:11:51 - present) - user has the id of Daniel99db (2025-01-24 02:11:50 - present) - user has the name of Daniel Chalef (2025-01-24 02:11:50 - present) # These are the most relevant entities # ENTITY_NAME: entity summary - worried: Daniel Chalef (Daniel99db) is feeling stressed lately, primarily due to work-related issues and concerns about his sick dog, which has made him worried. - Daniel99db: Daniel99db, or Daniel Chalef, is currently experiencing stress primarily due to work-related issues and concerns about his sick dog. Despite these challenges, he has shown a desire for interaction by initiating conversations, indicating his openness to communication. - sick: Daniel Chalef, also known as Daniel99db, is feeling stressed lately, primarily due to work-related issues and concerns about his sick dog. He expresses worry about his dog's health. - Daniel Chalef: Daniel Chalef, also known as Daniel99db, has been experiencing stress recently, primarily related to work issues and concerns about his sick dog. Despite this stress, he has been feeling generally well and has expressed a desire to connect with others, as indicated by his friendly greeting, "Hi there?". - dog: Daniel99db, also known as Daniel Chalef, mentioned that he has been feeling a bit stressed lately, which is related to both work and his dog. - work: Daniel Chalef, also known as Daniel99db, has been experiencing stress lately, primarily related to work. - feeling: The assistant initiates a conversation by asking how the user is feeling today, indicating a willingness to listen and provide support. ``` ```python r = await graph_invoke( "She ate my shoes which were expensive.", first_name, last_name, thread_id, ) print(r) ``` > That sounds really frustrating, especially when you care so much about your belongings and your dog's health. It's tough when pets get into things they shouldn't, and it can add to your stress. How are you feeling about that situation? Are you able to focus on her health despite the shoe incident? Let's now test whether the Agent is correctly grounded with facts from the prior conversation. ```python r = await graph_invoke( "What are we talking about?", first_name, last_name, thread_id, ) print(r) ``` > We were discussing your concerns about your dog being sick and the situation with her eating your expensive shoes. It sounds like you're dealing with a lot right now, and I want to make sure we're addressing what's on your mind. If there's something else you'd like to talk about or if you want to share more about your dog, I'm here to listen. Let's go even further back to determine whether context is kept by referencing a user message that is not currently in the Agent State. Zep will retrieve Facts related to the user's job. ```python r = await graph_invoke( "What have I said about my job?", first_name, last_name, thread_id, ) print(r) ``` > You've mentioned that you've been feeling a bit stressed lately, primarily due to work-related issues. If you'd like to share more about what's been going on at work or how it's affecting you, I'm here to listen and support you. # Autogen Memory Example > Autogen is a library created by Microsoft for building multi-agent applications. This example demonstrates using Zep for Autogen long-term memory. Autogen 4 has been released. This example is not compatible with Autogen 4. We'll be updating it soon! **NOTE** This example does not include all code required to run the Autogen Agents. A complete Notebook example of using Zep for Autogen long-term memory may be found in the [Zep Python SDK Repository](https://github.com/getzep/zep-python/blob/main/examples/autogen-agent/agent.ipynb). This example walks through how to build an Autogen Agent with long-term memory. Zep builds a knowledge graph from user interactions with the agent, enabling the agent to recall relevant facts from previous conversations or user interactions. In this example we will: * Create an Autogen Agent class that extends `ConversableAgent` by adding long-term memory * Create a Mental Health Assistant Agent, CareBot, that acts as a counselor and coach. * Create a user Agent, Cathy, who stands in for our expected user. * Demonstrate preloading chat history into Zep. * Demonstrate the agents in conversation, with CareBot recalling facts from previous conversations with Cathy. * Inspect Facts within Zep, and demonstrate how to use Zep's Fact Ratings to improve the quality of returned facts. ## Install dependencies ```bash pip install autogen zep-cloud ``` ## Import Autogen and configure define a `config_list` ```python import os from dotenv import load_dotenv import uuid from typing import Union, Dict from autogen import ConversableAgent, Agent load_dotenv() config_list = [ { "model": "gpt-4o-mini", "api_key": os.environ.get("OPENAI_API_KEY"), "max_tokens": 1024, } ] ``` ## initiualize the Zep Client You can sign up for a Zep account here: [https://www.getzep.com/](https://www.getzep.com/) ```python from zep_cloud.client import AsyncZep from zep_cloud import Message, FactRatingExamples, FactRatingInstruction MIN_FACT_RATING = 0.3 # Configure Zep zep = AsyncZep(api_key=os.environ.get("ZEP_API_KEY")) ``` ## ZepConversableAgent The `ZepConversableAgent` is a custom implementation of the Autogen `ConversableAgent` that integrates with Zep for long-term memory management. This class extends the functionality of the base `ConversableAgent` by adding Zep-specific features for persisting and retrieving facts from long-term memory. ```python class ZepConversableAgent(ConversableAgent): """ A custom ConversableAgent that integrates with Zep for long-term memory. """ def __init__( self, name: str, system_message: str, llm_config: dict, function_map: dict, human_input_mode: str, zep_session_id: str, ): super().__init__( name=name, system_message=system_message, llm_config=llm_config, function_map=function_map, human_input_mode=human_input_mode, ) self.zep_session_id = zep_session_id # store the original system message as we will update it with relevant facts from Zep self.original_system_message = system_message self.register_hook( "a_process_last_received_message", self.persist_user_messages ) self.register_hook( "a_process_message_before_send", self.persist_assistant_messages ) async def persist_assistant_messages( self, sender: Agent, message: Union[Dict, str], recipient: Agent, silent: bool ): """Agent sends a message to the user. Add the message to Zep.""" # Assume message is a string zep_messages = convert_to_zep_messages( [{"role": "assistant", "name": self.name, "content": message}] ) await zep.memory.add(session_id=self.zep_session_id, messages=zep_messages) return message async def persist_user_messages(self, messages: list[dict[str, str]] | str): """ User sends a message to the agent. Add the message to Zep and update the system message with relevant facts from Zep. """ # Assume messages is a string zep_messages = convert_to_zep_messages([{"role": "user", "content": messages}]) await zep.memory.add(session_id=self.zep_session_id, messages=zep_messages) memory = await zep.memory.get(self.zep_session_id, min_rating=MIN_FACT_RATING) # Update the system message with the relevant facts retrieved from Zep self.update_system_message( self.original_system_message + f"\n\nRelevant facts about the user and their prior conversation:\n{memory.relevant_facts}" ) return messages ``` ## Zep User and Session Management ### Zep User A [Zep User](/users) represents an individual interacting with your application. Each User can have multiple Sessions associated with them, allowing you to track and manage interactions over time. The unique identifier for each user is their `UserID`, which can be any string value (e.g., username, email address, or UUID). ### Zep Session A [Zep Session](/concepts) represents a conversation and can be associated with Users in a one-to-many relationship. Chat messages are added to Sessions, with each session having many messages. ### Fact Rating [Fact Rating](/facts) is a feature in Zep that allows you to rate the importance or relevance of facts extracted from conversations. This helps in prioritizing and filtering information when retrieving memory artifacts. Here, we rate facts based on poignancy. We provide a definition of poignancy and several examples of highly poignant and low-poignancy facts. When retrieving memory, you can use the `min_rating` parameter to filter facts based on their importance. Fact Rating helps ensure the most relevant information, especially in long or complex conversations, is used to ground the agent. ```python bot_name = "CareBot" user_name = "Cathy" user_id = user_name + str(uuid.uuid4())[:4] session_id = str(uuid.uuid4()) fact_rating_instruction = """Rate the facts by poignancy. Highly poignant facts have a significant emotional impact or relevance to the user. Low poignant facts are minimally relevant or of little emotional significance.""" fact_rating_examples = FactRatingExamples( high="The user received news of a family member's serious illness.", medium="The user completed a challenging marathon.", low="The user bought a new brand of toothpaste.", ) await zep.user.add(user_id=user_id, fact_rating_instruction=FactRatingInstruction( instruction=fact_rating_instruction, examples=fact_rating_examples, ) ) ``` ## Preload a prior conversation into Zep We'll load a prior conversation into long-term memory. We'll use facts derived from this conversation when Cathy restarts the conversation with CareBot, ensuring Carebot has context. ```python chat_history = [ { "role": "assistant", "name": "carebot", "content": "Hi Cathy, how are you doing today?", }, { "role": "user", "name": "Cathy", "content": "To be honest, I've been feeling a bit down and demotivated lately. It's been tough.", }, { "role": "assistant", "name": "CareBot", "content": "I'm sorry to hear that you're feeling down and demotivated, Cathy. It's understandable given the challenges you're facing. Can you tell me more about what's been going on?", }, { "role": "user", "name": "Cathy", "content": "Well, I'm really struggling to process the passing of my mother.", }, { "role": "assistant", "name": "CareBot", "content": "I'm deeply sorry for your loss, Cathy. Losing a parent is incredibly difficult. It's normal to struggle with grief, and there's no 'right' way to process it. Would you like to talk about your mother or how you're coping?", }, { "role": "user", "name": "Cathy", "content": "Yes, I'd like to talk about my mother. She was a kind and loving person.", }, ] # Convert chat history to Zep messages zep_messages = convert_to_zep_messages(chat_history) await zep.memory.add(session_id=session_id, messages=zep_messages) ``` ## Review all facts in Zep We query all session facts for this user session. Only facts that meet the `MIN_FACT_RATING` threshold are returned. ```python response = await zep.memory.get(session_id=session_id, min_rating=MIN_FACT_RATING) for r in response.relevant_facts: print(r) ``` ```text created_at='2024-10-07T20:04:11.98139Z' fact='Cathy has been feeling down and demotivated lately.' rating=0.5 uuid_='17183c18-381b-45d2-82ea-0c06317acf6f' created_at='2024-10-07T20:04:11.98139Z' fact='Cathy describes her mother as a kind and loving person.' rating=0.5 uuid_='cd6b2e6d-b287-4d92-9de5-d4ee6e82111e' created_at='2024-10-07T20:04:11.98139Z' fact='Cathy is struggling to process the passing of her mother.' rating=0.75 uuid_='bb2f100c-2f12-4976-9026-b322c29e457e' ``` ## Create the Autogen agent, CareBot, an instance of `ZepConversableAgent` We pass in the current `session_id` into the CareBot agent which allows it to retrieve relevant facts related to the conversation with Cathy. ```python carebot_system_message = """ You are a compassionate mental health bot and caregiver. Review information about the user and their prior conversation below and respond accordingly. Keep responses empathetic and supportive. And remember, always prioritize the user's well-being and mental health. Keep your responses very concise and to the point. """ agent = ZepConversableAgent( bot_name, system_message=carebot_system_message, llm_config={"config_list": config_list}, function_map=None, # No registered functions, by default it is None. human_input_mode="NEVER", # Never ask for human input. zep_session_id=session_id, ) ``` ## Create the Autogen agent, Cathy Cathy is a stand-in for a human. When building a production application, you'd replace Cathy with a human-in-the-loop pattern. **Note** that we're instructing Cathy to start the conversation with CareBit by asking about her previous session. This is an opportunity for us to test whether fact retrieval from Zep's long-term memory is working. ```python cathy = ConversableAgent( user_name, system_message="You are a helpful mental health bot. You are seeking counsel from a mental health bot. Ask the bot about your previous conversation.", llm_config={"config_list": config_list}, human_input_mode="NEVER", # Never ask for human input. ) ``` ## Start the conversation We use Autogen's `a_initiate_chat` method to get the two agents conversing. CareBot is the primary agent. **NOTE** how Carebot is able to recall the past conversation about Cathy's mother in detail, having had relevant facts from Zep added to its system prompt. ```python result = await agent.a_initiate_chat( cathy, message="Hi Cathy, nice to see you again. How are you doing today?", max_turns=3, ) ``` ```text CareBot (to Cathy): Hi Cathy, nice to see you again. How are you doing today? -------------------------------------------------------------------------------- Cathy (to CareBot): Hello CareBot! I'm doing well, thank you for asking. I wanted to reflect on our previous conversation—do you remember what we discussed? It would be helpful to revisit that topic and explore it further if you’re up for it! -------------------------------------------------------------------------------- CareBot (to Cathy): Of course, Cathy. We talked about your difficulty in processing your mother’s passing and how you've been feeling down and demotivated lately. It's completely natural to have these feelings, especially after such a significant loss. What would you like to explore further? -------------------------------------------------------------------------------- Cathy (to CareBot): Cathy: Thank you for reminding me, CareBot. Yes, I’ve been struggling with those feelings, and it’s been tough to navigate. I’d like to explore some coping strategies to help me process my grief. Are there any techniques or practices you would recommend? -------------------------------------------------------------------------------- CareBot (to Cathy): Absolutely, Cathy. Here are some coping strategies to help you navigate your grief: 1. **Journaling**: Writing your thoughts and feelings can be a great outlet and help you process your emotions. 2. **Talk to someone**: Sharing your feelings with a trusted friend or therapist can provide support and understanding. 3. **Mindfulness and meditation**: These practices can help ground you and create a sense of calm amid emotional turmoil. 4. **Create a tribute**: Honoring your mother through a scrapbook, writing letters, or lighting a candle can foster connection and memory. 5. **Physical activity**: Engaging in exercise can boost your mood and help alleviate stress. Remember, it's important to be gentle with yourself as you navigate this process. What resonates with you? -------------------------------------------------------------------------------- Cathy (to CareBot): Cathy: Thank you for those suggestions, CareBot. I really like the idea of journaling and creating a tribute for my mother; it sounds like a meaningful way to express my feelings. I also think mindfulness could help me find some peace amidst the sadness. Do you have any specific tips on how to start journaling or practicing mindfulness? -------------------------------------------------------------------------------- ``` ## Review current facts in Zep Let's see how the facts have evolved as the conversation has progressed. ```python response = await zep.memory.get(session_id, min_rating=MIN_FACT_RATING) for r in response.relevant_facts: print(r) ``` ```text created_at='2024-10-07T20:04:28.397184Z' fact="Cathy wants to reflect on a previous conversation about her mother and explore the topic of her mother's passing further." rating=0.75 uuid_='56488eeb-d8ac-4b2f-8acc-75f71b56ad76' created_at='2024-10-07T20:04:28.397184Z' fact='Cathy is struggling to process the passing of her mother and has been feeling down and demotivated lately.' rating=0.75 uuid_='0fea3f05-ed1a-4e39-a092-c91f8af9e501' created_at='2024-10-07T20:04:28.397184Z' fact='Cathy describes her mother as a kind and loving person.' rating=0.5 uuid_='131de203-2984-4cba-9aef-e500611f06d9' ``` ## Search over Facts in Zep's long-term memory In addition to the `memory.get` method which uses the current conversation to retrieve relevant\_facts, we can also search Zep with our own keywords. Here, we retrieve facts using a query. The `zep.graph.search` API may be used as an Agent tool, enabling an agent to search across user memory for facts. ```python response = await zep.graph.search( query="What do you know about Cathy's family?", user_id=user_id, ) relevant_edges = response.edges formatted_facts = [] for edge in relevant_edges: valid_at = edge.valid_at if edge.valid_at is not None else "date unknown" invalid_at = edge.invalid_at if edge.invalid_at is not None else "present" formatted_fact = f"{edge.fact} (Date range: {valid_at} - {invalid_at})" formatted_facts.append(formatted_fact) # Print the results print("\nFound facts:") for fact in formatted_facts: print(f"- {fact}") ``` ```text created_at='2024-10-07T20:04:28.397184Z' fact="Cathy wants to reflect on a previous conversation about her mother and explore the topic of her mother's passing further." rating=0.75 uuid_='56488eeb-d8ac-4b2f-8acc-75f71b56ad76' created_at='2024-10-07T20:04:28.397184Z' fact='Cathy is struggling to process the passing of her mother and has been feeling down and demotivated lately.' rating=0.75 uuid_='0fea3f05-ed1a-4e39-a092-c91f8af9e501' created_at='2024-10-07T20:04:28.397184Z' fact='Cathy describes her mother as a kind and loving person.' rating=0.5 uuid_='131de203-2984-4cba-9aef-e500611f06d9' ``` # Mem0 Migration > How to migrate from Mem0 to Zep Zep is a memory layer for AI agents that unifies chat and business data into a dynamic [temporal knowledge graph](/concepts#the-knowledge-graph) for each user. It tracks entities, relationships, and facts as they evolve, enabling you to build prompts with only the most relevant information—reducing hallucinations, improving recall, and lowering LLM costs. Zep provides high-level APIs like `memory.get` and deep search with `graph.search`, supports custom entity/edge types, fact ratings, hybrid search, and granular graph updates. Mem0, by comparison, offers basic add/get/search APIs and an optional graph, but lacks built-in data unification, ontology customization, temporal fact management, fact ratings, and fine-grained graph control. Got lots of data to migrate? [Contact us](mailto:[email protected]) for a discount and increased API limits. ## Zep's memory model in one minute ### Unified customer record * Messages sent via [`memory.add`](memory#adding-memory) go straight into the user's knowledge graph; business objects (JSON, docs, e-mails, CRM rows) flow in through [`graph.add`](/adding-data-to-the-graph). Zep automatically deduplicates entities and keeps every fact's *valid* and *invalid* dates so you always see the latest truth. ### Domain-depth ontology * You can define Pydantic-style **[custom entity and edge classes](/customizing-graph-structure)** so the graph speaks your business language (Accounts, Policies, Devices, etc.). ### Temporal facts & ratings * Every edge stores when a fact was created, became valid, was invalidated, and (optionally) expired; [`fact_ratings`](/facts) let you auto-label facts (e.g., "high-confidence KYC data") and filter on retrieval. ### Hybrid & granular search * [`graph.search`](/searching-the-graph) supports [hybrid BM25 + semantic queries, graph search](/searching-the-graph), with pluggable rerankers (RRF, MMR, cross-encoder) and can target nodes, edges, episodes, or everything at once. ## How Zep differs from Mem0 | Capability | **Zep** | **Mem0** | | ----------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | | **Business-data ingestion** | Native via [`graph.add`](/adding-data-to-the-graph) (JSON or text); [business facts merge with user graph](/concepts#business-data-vs-chat-message-data) | No direct ingestion API; business data must be rewritten as "memories" or loaded into external graph store | | **Knowledge-graph storage** | Built-in [temporal graph](/concepts#managing-changes-in-facts-over-time); zero infra for developers | Optional "Graph Memory" layer that *requires* Neo4j/Memgraph and extra config | | **Custom ontology** | First-class [entity/edge type system](/customizing-graph-structure) | Not exposed; relies on generic nodes/relationships | | **Fact life-cycle (valid/invalid)** | [Automatic and queryable](/concepts#managing-changes-in-facts-over-time) | Not documented / not supported | | **Fact ratings & filtering** | Yes ([`fact_ratings` API](/facts)) | Not available | | **Search** | [Hybrid vector + graph search](/searching-the-graph) with multiple rerankers | Vector search with filters; basic Cypher queries if graph layer enabled | | **Graph CRUD** | Full [node/edge CRUD](/deleting-data-from-the-graph) & [bulk episode ingest](/adding-data-to-the-graph) | Add/Delete memories; no low-level edge ops | | **Memory context string** | [Auto-generated, temporal, prompt-ready](/concepts#memory-context) | You assemble snippets manually from `search` output | | **LLM integration** | Returns [ready-made `memory.context`](/concepts#memory-context); easily integrates with agentic tools | Returns raw strings you must format | ## SDK support Zep offers Python, TypeScript, and Go SDKs. See [Installation Instructions](/quickstart) for more details. ## Migrating your code ### Basic flows | **What you do in Mem0** | **Do this in Zep** | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `client.add(messages, user_id=ID)` → stores conversation snippets | `zep.memory.add(session_id, messages=[...])` – keeps chat sequence **and** updates graph | | `client.add("json...", user_id=ID)` (not really supported) | `zep.graph.add(user_id, data=)` – drop raw business records right in | | `client.search(query, user_id=ID)` – vector+filter search | *Easy path*: `zep.memory.get(session_id)` returns the `memory.context` + recent messages
*Deep path*: `zep.graph.search(user_id, query, reranker="rrf")` | | `client.get_all(user_id=ID)` – list memories | `zep.graph.search(user_id, '')` or iterate `graph.get_nodes/edges` for full dump | | `client.update(memory_id, ...)` / `delete` | `zep.graph.edge.delete(uuid_="edge_uuid")` or `zep.graph.episode.delete(uuid_="episode_uuid")` for granular edits. Facts may not be updated directly; new data automatically invalidates old. | ### Practical tips * **Session mapping:** Map Mem0's `user_id` → Zep `user_id`, and create `session_id` per conversation thread. * **Business objects:** Convert external records to JSON or text and feed them through `graph.add`; Zep will handle entity linking automatically. * **Prompting:** Replace your custom "summary builder" with the `memory.context` string; it already embeds temporal ranges and entity summaries. * **Quality filters:** Use Fact Ratings and apply `min_fact_rating` when calling `memory.get` to exclude low-confidence facts instead of manual post-processing. * **Search tuning:** Start with the default `rrf` reranker; switch to `mmr`, `node_distance`, `cross_encoder`, or `episode_mentions` when you need speed or precision tweaks. ## Side-by-side SDK cheat-sheet | **Operation** | Mem0 Method (Python) | Zep Method (Python) | Notes | | ------------------------ | ------------------------------ | ---------------------------------------------------- | --------------------------------------------- | | Add chat messages | `m.add(messages, user_id=...)` | `zep.memory.add(session_id, messages)` | Zep expects *ordered* AI + user msgs per turn | | Add business record | *n/a* (work-around) | `zep.graph.add(user_id, data)` | Direct ingestion of JSON/text | | Retrieve context | `m.search(query,... )` | `zep.memory.get(session_id)` | Zep auto-selects facts; no prompt assembly | | Semantic / hybrid search | `m.search(query, ...)` | `zep.graph.search(..., reranker=...)` | Multiple rerankers, node/edge scopes | | List memories | `m.get_all(user_id)` | `zep.graph.search(user_id, '')` | Empty query lists entire graph | | Update fact | `m.update(id, ...)` | *Not directly supported* - add new data to supersede | Facts are temporal; new data invalidates old | | Delete fact | `m.delete(id)` | `zep.graph.edge.delete(uuid_="edge_uuid")` | Episode deletion removes associated edges | | Rate / filter facts | *not supported* | `min_fact_rating` param on `memory.get` | — | ## Where to dig deeper * [**Quickstart**](/quickstart) * [**Graph Search guide**](/searching-the-graph) * [**Entity / Edge customization**](/customizing-graph-structure) * [**Fact ratings**](/facts) * **Graph CRUD**: [Reading from the Graph](/reading-data-from-the-graph) | [Adding to the Graph](/adding-data-to-the-graph) | [Deleting from the Graph](/deleting-data-from-the-graph) For any questions, ping the Zep Discord or contact your account manager. Happy migrating! # FAQ Yes - Zep offers a free tier. See [Pricing](https://www.getzep.com/pricing) for more information. The API URL for Zep Cloud is `https://api.getzep.com`. Note that you do not need to specify the API URL when using the Cloud SDKs. If a service requests the Zep URL, it is possible it's only compatible with the Zep Community Edition service. We have official multilingual support on our roadmap, enabling the creation of graphs in a user’s own language. Currently, graphs are not explicitly created in the user’s language. However, Zep should work well today with any language, provided you're using a multilingual LLM and your own prompts explicitly state that responses to the user should be in their language. # Privacy Policy **Version 1.0** **Last revised on: January 27^th^, 2024** Zep Software, Inc. (the "Company") is committed to maintaining robust privacy protections for its users.  Our Privacy Policy ("Privacy Policy") is designed to help you understand how we collect, use and safeguard the information you provide to us and to assist you in making informed decisions when using our Service.   For purposes of this Agreement, "Site" refers to the Company's website properties, which can be accessed at the getzep.com Internet domain. "Service" refers to the Company's services accessed via the Site, in which users can view Company marketing material, register for the Company's services, access support and help resources, and other services and resources that may be made available from time to time. The terms "we," "us," and "our" refer to the Company. "You" refers to you, as a user of our Site or our Service. By accessing our Site or our Service, you accept our Privacy Policy and [Terms of Use](website-terms-of-use), and you consent to our collection, storage, use and disclosure of your Personal Information as described in this Privacy Policy. 1. INFORMATION WE COLLECT We collect "Non-Personal Information" and "Personal Information." **Non-Personal Information** includes information that cannot be used to personally identify you, such as anonymous usage data, general demographic information we may collect, referring/exit pages and URLs, platform types, preferences you submit and preferences that are generated based on the data you submit and number of clicks. **Personal Information** includes your email and name which you submit to us through the registration process at the Site. 1.1. *Information collected via Technology* To activate the Service you do not need to submit any Personal Information other than your email address and name. To use the Service thereafter, you do not need to submit further Personal Information. However, in an effort to improve the quality of the Service, we track information provided to us by your browser or by our software application when you view or use the Service, such as the website you came from (known as the "referring URL"), the type of browser you use, the device from which you connected to the Service, the time and date of access, and other information that does not personally identify you. We track this information using cookies, or small text files which include an anonymous unique identifier. Cookies are sent to a user's browser from our servers and are stored on the user's computer hard drive. Sending a cookie to a user's browser enables us to collect Non-Personal information about that user and keep a record of the user's preferences when utilizing our services, both on an individual and aggregate basis. For example, the Company may use cookies to collect the following information: * how often you use our websites and services * which content and features you use The Company may use both persistent and session cookies; persistent cookies remain on your computer after you close your session and until you delete them, while session cookies expire when you close your browser. 1.2. *Information you provide us by registering for an account* In addition to the information provided automatically by your browser when you visit the Site, to become a subscriber to the Service you will need to create a personal profile. You can create a profile by registering with the Service and entering your email address, and creating a user name and a password. By registering, you are authorizing us to collect, store and use your email address in accordance with this Privacy Policy. 1.3. *Children's Privacy* The Site and the Service are not directed to anyone under the age of 13. The Site does not knowingly collect or solicit information from anyone under the age of 13, or allow anyone under the age of 13 to sign up for the Service. In the event that we learn that we have gathered personal information from anyone under the age of 13 without the consent of a parent or guardian, we will delete that information as soon as possible. If you believe we have collected such information, please contact us at [[email protected]](mailto:[email protected]). 2. HOW WE USE AND SHARE INFORMATION *Personal Information:* Except as otherwise stated in this Privacy Policy, we do not sell, trade, rent or otherwise share for marketing purposes your Personal Information with third parties without your consent. We do share Personal Information with vendors who are performing services for the Company, such as the servers for our email communications who are provided access to user's email address for purposes of sending emails from us. Those vendors use your Personal Information only at our direction and in accordance with our Privacy Policy. In general, the Personal Information you provide to us is used to help us communicate with you. For example, we use Personal Information to contact users in response to questions, solicit feedback from users, provide technical support, and inform users about promotional offers. We may share Personal Information with outside parties if we have a good-faith belief that access, use, preservation or disclosure of the information is reasonably necessary to meet any applicable legal process or enforceable governmental request; to enforce applicable Terms of Service, including investigation of potential violations; address fraud, security or technical concerns; or to protect against harm to the rights, property, or safety of our users or the public as required or permitted by law. *Non-Personal Information* In general, we use Non-Personal Information to help us improve the Service and customize the user experience. We also aggregate Non-Personal Information in order to track trends and analyze use patterns on the Site. This Privacy Policy does not limit in any way our use or disclosure of Non-Personal Information and we reserve the right to use and disclose such Non-Personal Information to our partners, advertisers and other third parties at our discretion. In the event we undergo a business transaction such as a merger, acquisition by another company, or sale of all or a portion of our assets, your Personal Information may be among the assets transferred. You acknowledge and consent that such transfers may occur and are permitted by this Privacy Policy, and that any acquirer of our assets may continue to process your Personal Information as set forth in this Privacy Policy. If our information practices change at any time in the future, we will post the policy changes to the Site so that you may opt out of the new information practices. We suggest that you check the Site periodically if you are concerned about how your information is used. 3. HOW WE PROTECT INFORMATION We implement security measures designed to protect your information from unauthorized access. Your account is protected by your account password and we urge you to take steps to keep your personal information safe by not disclosing your password and by logging out of your account after each use. We further protect your information from potential security breaches by implementing certain technological security measures including encryption, firewalls and secure socket layer technology. However, these measures do not guarantee that your information will not be accessed, disclosed, altered or destroyed by breach of such firewalls and secure server software. By using our Service, you acknowledge that you understand and agree to assume these risks. 4. YOUR RIGHTS REGARDING THE USE OF YOUR PERSONAL INFORMATION You have the right at any time to prevent us from contacting you for marketing purposes.  When we send a promotional communication to a user, the user can opt out of further promotional communications by following the unsubscribe instructions provided in each promotional e-mail.\ Please note that notwithstanding the promotional preferences you indicate by either unsubscribing, we may continue to send you administrative emails including, for example, periodic updates to our Privacy Policy. 5. LINKS TO OTHER WEBSITES As part of the Service, we may provide links to or compatibility with other websites or applications. However, we are not responsible for the privacy practices employed by those websites or the information or content they contain. This Privacy Policy applies solely to information collected by us through the Site and the Service. Therefore, this Privacy Policy does not apply to your use of a third party website accessed by selecting a link on our Site or via our Service. To the extent that you access or use the Service through or on another website or application, then the privacy policy of that other website or application will apply to your access or use of that site or application. We encourage our users to read the privacy statements of other websites before proceeding to use them. 6. CHANGES TO OUR PRIVACY POLICY The Company reserves the right to change this policy and our Terms of Service at any time.  We will notify you of significant changes to our Privacy Policy by sending a notice to the primary email address specified in your account or by placing a prominent notice on our site. Significant changes will go into effect 30 days following such notification. Non-material changes or clarifications will take effect immediately. You should periodically check the Site and this privacy page for updates. 7. CONTACT US If you have any questions regarding this Privacy Policy or the practices of this Site, please contact us by sending an email to [[email protected]](mailto:[email protected]). # Terms of Service **Version 1.0** **Last revised on: January 27^th^, 2024** If you signed a separate Cover Page to access the Product with the same account, and that agreement has not ended, the terms below do not apply to you. Instead, your separate Cover Page applies to your use of the Product. This Agreement is between Zep Software, Inc. and the company or person accessing or using the Product. This Agreement consists of: (1) the Order Form and (2) the Key Terms, both of which are on the Cover Page below, and (3) the Common Paper [Cloud Service Agreement Standard Terms Version 1.1](https://commonpaper.com/standards/cloud-service-agreement/1.1/) ("Standard Terms"). Any modifications to the Standard Terms made in the Cover Page will control over conflicts with the Standard Terms. Capitalized words have the meanings or descriptions given in the Cover Page or the Standard Terms. If you are accessing or using the Product on behalf of your company, you represent that you are authorized to accept this Agreement ßon behalf of your company. By signing up, accessing, or using the Product, Customer indicates its acceptance of this Agreement and agrees to be bound by the terms and conditions of this Agreement. Cover Page *Order Form* **Cloud Service:** Zep is a cloud-based platform-as-a-service that offers fast, scalable, privacy-compliant building blocks for Generative AI apps. **Subscription Start Date:** The Effective Date **Subscription Period:** 1 month(s) **Non-Renewal Notice Period:** At least 30 days before the end of the current Subscription Period. **Cloud Service Fees:** Section 5.2 of the Standard Terms is replaced with: Certain parts of the Product have different pricing plans, which are available at Provider's [pricing page](https://www.getzep.com/pricing). Within the Payment Period, Customer will pay Provider fees based on the Product tier selected at the time of account creation and Customer's usage per Subscription Period. Provider may update Product pricing by giving at least 30 days notice to Customer (including by email or notification within the Product), and the change will apply in the next Subscription Period. **Payment Period:** 5 day(s) from the last day of the Subscription Period **Invoice Period:** Monthly *Key Terms* **Customer:** The company or person who accesses or uses the Product. If the person accepting this Agreement is doing so on behalf of a company, all use of the word "Customer" in the Agreement will mean that company. **Provider:** Zep Software, Inc. **Effective Date:** The date Customer first accepts this Agreement. **Covered Claims:** **Provider Covered Claims:** Any action, proceeding, or claim that the Cloud Service, when used by Customer according to the terms of the Agreement, violates, misappropriates, or otherwise infringes upon anyone else's intellectual property or other proprietary rights. **Customer Covered Claims:** Any action, proceeding, or claim that (1) the Customer Content, when used according to the terms of the Agreement, violates, misappropriates, or otherwise infringes upon anyone else's intellectual property or other proprietary rights; or (2) results from Customer's breach or alleged breach of Section 2.1 (Restrictions on Customer). **General Cap Amount:** The fees paid or payable by Customer to provider in the 12 month period immediately before the claim **Governing Law:** The laws of the State of Delaware **Chosen Courts:** The state or federal courts located in Delaware **Notice Address:** For Provider: [[email protected]](mailto:[email protected]) For Customer: The main email address on Customer's account *Changes to the Standard Terms* **Publicity Rights:** Modifying Section 14.7 of the Standard Terms, Provider may identify Customer and use Customer's logo and trademarks on Provider's website and in marketing materials to identify Customer as a user of the Product. Customer hereby grants Provider a non-exclusive, royalty-free license to do so in connection with any marketing, promotion, or advertising of Provider or the Product during the length of the Agreement. # Website Terms of Use **Version 1.0** **Last revised on: January 27^th^, 2024** The website located at getzep.com (the "**Site**") is a copyrighted work belonging to Zep Software, Inc. ("**Company**", "**us**", "**our**", and "**we**"). Certain features of the Site may be subject to additional guidelines, terms, or rules, which will be posted on the Site in connection with such features. All such additional terms, guidelines, and rules are incorporated by reference into these Terms. These Terms of Use (these "**Terms**") set forth the legally binding terms and conditions that govern your use of the Site. By accessing or using the Site, you are accepting these Terms (on behalf of yourself or the entity that you represent), and you represent and warrant that you have the right, authority, and capacity to enter into these Terms (on behalf of yourself or the entity that you represent). you may not access or use the Site or accept the Terms if you are not at least 18 years old. If you do not agree with all of the provisions of these Terms, do not access and/or use the Site. **PLEASE BE AWARE THAT SECTION 8.2 CONTAINS PROVISIONS GOVERNING HOW TO RESOLVE DISPUTES BETWEEN YOU AND COMPANY. AMONG OTHER THINGS, SECTION 8.2 INCLUDES AN AGREEMENT TO ARBITRATE WHICH REQUIRES, WITH LIMITED EXCEPTIONS, THAT ALL DISPUTES BETWEEN YOU AND US SHALL BE RESOLVED BY BINDING AND FINAL ARBITRATION. SECTION 8.2 ALSO CONTAINS A CLASS ACTION AND JURY TRIAL WAIVER. PLEASE READ SECTION 8.2 CAREFULLY.** **UNLESS YOU OPT OUT OF THE AGREEMENT TO ARBITRATE WITHIN 30 DAYS: (1) YOU WILL ONLY BE PERMITTED TO PURSUE DISPUTES OR CLAIMS AND SEEK RELIEF AGAINST US ON AN INDIVIDUAL BASIS, NOT AS A PLAINTIFF OR CLASS MEMBER IN ANY CLASS OR REPRESENTATIVE ACTION OR PROCEEDING AND YOU WAIVE YOUR RIGHT TO PARTICIPATE IN A CLASS ACTION LAWSUIT OR CLASS-WIDE ARBITRATION; AND (2) YOU ARE WAIVING YOUR RIGHT TO PURSUE DISPUTES OR CLAIMS AND SEEK RELIEF IN A COURT OF LAW AND TO HAVE A JURY TRIAL.** 1. **Accounts** 1.1. **Account Creation.** In order to use certain features of the Site, you must register for an account ("**Account**") and provide certain information about yourself as prompted by the account registration form. You represent and warrant that: (a) all required registration information you submit is truthful and accurate; (b) you will maintain the accuracy of such information. You may delete your Account at any time, for any reason, by following the instructions on the Site. Company may suspend or terminate your Account in accordance with Section 7. 1.2. **Account Responsibilities.** You are responsible for maintaining the confidentiality of your Account login information and are fully responsible for all activities that occur under your Account. You agree to immediately notify Company of any unauthorized use, or suspected unauthorized use of your Account or any other breach of security. Company cannot and will not be liable for any loss or damage arising from your failure to comply with the above requirements. 2. **Access to the Site** 2.1. **License.** Subject to these Terms, Company grants you a non-transferable, non-exclusive, revocable, limited license to use and access the Site solely for your own personal, noncommercial use. 2.2. **Certain Restrictions.** The rights granted to you in these Terms are subject to the following restrictions: (a) you shall not license, sell, rent, lease, transfer, assign, distribute, host, or otherwise commercially exploit the Site, whether in whole or in part, or any content displayed on the Site; (b) you shall not modify, make derivative works of, disassemble, reverse compile or reverse engineer any part of the Site; (c) you shall not access the Site in order to build a similar or competitive website, product, or service; and (d) except as expressly stated herein, no part of the Site may be copied, reproduced, distributed, republished, downloaded, displayed, posted or transmitted in any form or by any means. Unless otherwise indicated, any future release, update, or other addition to functionality of the Site shall be subject to these Terms. All copyright and other proprietary notices on the Site (or on any content displayed on the Site) must be retained on all copies thereof. 2.3. **Modification.** Company reserves the right, at any time, to modify, suspend, or discontinue the Site (in whole or in part) with or without notice to you. You agree that Company will not be liable to you or to any third party for any modification, suspension, or discontinuation of the Site or any part thereof. 2.4. **No Support or Maintenance.** You acknowledge and agree that Company will have no obligation to provide you with any support or maintenance in connection with the Site. 2.5. **Ownership.** You acknowledge that all the intellectual property rights, including copyrights, patents, trade marks, and trade secrets, in the Site and its content are owned by Company or Company's suppliers. Neither these Terms (nor your access to the Site) transfers to you or any third party any rights, title or interest in or to such intellectual property rights, except for the limited access rights expressly set forth in Section 2.1. Company and its suppliers reserve all rights not granted in these Terms. There are no implied licenses granted under these Terms. 2.6. **Feedback.** If you provide Company with any feedback or suggestions regarding the Site ("**Feedback**"), you hereby assign to Company all rights in such Feedback and agree that Company shall have the right to use and fully exploit such Feedback and related information in any manner it deems appropriate. Company will treat any Feedback you provide to Company as non-confidential and non-proprietary. You agree that you will not submit to Company any information or ideas that you consider to be confidential or proprietary. 3. **Indemnification.** You agree to indemnify and hold Company (and its officers, employees, and agents) harmless, including costs and attorneys' fees, from any claim or demand made by any third party due to or arising out of (a) your use of the Site, (b) your violation of these Terms or (c) your violation of applicable laws or regulations. Company reserves the right, at your expense, to assume the exclusive defense and control of any matter for which you are required to indemnify us, and you agree to cooperate with our defense of these claims. You agree not to settle any matter without the prior written consent of Company. Company will use reasonable efforts to notify you of any such claim, action or proceeding upon becoming aware of it. 4. **Third-Party Links & Ads; Other Users** 4.1. **Third-Party Links & Ads.** The Site may contain links to third-party websites and services, and/or display advertisements for third parties (collectively, "**Third-Party Links & Ads**"). Such Third-Party Links & Ads are not under the control of Company, and Company is not responsible for any Third-Party Links & Ads. Company provides access to these Third-Party Links & Ads only as a convenience to you, and does not review, approve, monitor, endorse, warrant, or make any representations with respect to Third-Party Links & Ads. You use all Third-Party Links & Ads at your own risk, and should apply a suitable level of caution and discretion in doing so. When you click on any of the Third-Party Links & Ads, the applicable third party's terms and policies apply, including the third party's privacy and data gathering practices. You should make whatever investigation you feel necessary or appropriate before proceeding with any transaction in connection with such Third-Party Links & Ads. 4.2. **Other Users.** Your interactions with other Site users are solely between you and such users. You agree that Company will not be responsible for any loss or damage incurred as the result of any such interactions. If there is a dispute between you and any Site user, we are under no obligation to become involved. 4.3.. **Release.** You hereby release and forever discharge Company (and our officers, employees, agents, successors, and assigns) from, and hereby waive and relinquish, each and every past, present and future dispute, claim, controversy, demand, right, obligation, liability, action and cause of action of every kind and nature (including personal injuries, death, and property damage), that has arisen or arises directly or indirectly out of, or that relates directly or indirectly to, the Site (including any interactions with, or act or omission of, other Site users or any Third-Party Links & Ads). IF YOU ARE A CALIFORNIA RESIDENT, YOU HEREBY WAIVE CALIFORNIA CIVIL CODE SECTION 1542 IN CONNECTION WITH THE FOREGOING, WHICH STATES: "A GENERAL RELEASE DOES NOT EXTEND TO CLAIMS WHICH THE CREDITOR OR RELEASING PARTY DOES NOT KNOW OR SUSPECT TO EXIST IN HIS OR HER FAVOR AT THE TIME OF EXECUTING THE RELEASE, WHICH IF KNOWN BY HIM OR HER MUST HAVE MATERIALLY AFFECTED HIS OR HER SETTLEMENT WITH THE DEBTOR OR RELEASED PARTY." 5. **Disclaimers** THE SITE IS PROVIDED ON AN "AS-IS" AND "AS AVAILABLE" BASIS, AND COMPANY (AND OUR SUPPLIERS) EXPRESSLY DISCLAIM ANY AND ALL WARRANTIES AND CONDITIONS OF ANY KIND, WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING ALL WARRANTIES OR CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, QUIET ENJOYMENT, ACCURACY, OR NON-INFRINGEMENT. WE (AND OUR SUPPLIERS) MAKE NO WARRANTY THAT THE SITE WILL MEET YOUR REQUIREMENTS, WILL BE AVAILABLE ON AN UNINTERRUPTED, TIMELY, SECURE, OR ERROR-FREE BASIS, OR WILL BE ACCURATE, RELIABLE, FREE OF VIRUSES OR OTHER HARMFUL CODE, COMPLETE, LEGAL, OR SAFE. IF APPLICABLE LAW REQUIRES ANY WARRANTIES WITH RESPECT TO THE SITE, ALL SUCH WARRANTIES ARE LIMITED IN DURATION TO 90 DAYS FROM THE DATE OF FIRST USE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT APPLY TO YOU. SOME JURISDICTIONS DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, SO THE ABOVE LIMITATION MAY NOT APPLY TO YOU. 6. **Limitation on Liability** TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL COMPANY (OR OUR SUPPLIERS) BE LIABLE TO YOU OR ANY THIRD PARTY FOR ANY LOST PROFITS, LOST DATA, COSTS OF PROCUREMENT OF SUBSTITUTE PRODUCTS, OR ANY INDIRECT, CONSEQUENTIAL, EXEMPLARY, INCIDENTAL, SPECIAL OR PUNITIVE DAMAGES ARISING FROM OR RELATING TO THESE TERMS OR YOUR USE OF, OR INABILITY TO USE, THE SITE, EVEN IF COMPANY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. ACCESS TO, AND USE OF, THE SITE IS AT YOUR OWN DISCRETION AND RISK, AND YOU WILL BE SOLELY RESPONSIBLE FOR ANY DAMAGE TO YOUR DEVICE OR COMPUTER SYSTEM, OR LOSS OF DATA RESULTING THEREFROM. TO THE MAXIMUM EXTENT PERMITTED BY LAW, NOTWITHSTANDING ANYTHING TO THE CONTRARY CONTAINED HEREIN, OUR LIABILITY TO YOU FOR ANY DAMAGES ARISING FROM OR RELATED TO THESE TERMS (FOR ANY CAUSE WHATSOEVER AND REGARDLESS OF THE FORM OF THE ACTION), WILL AT ALL TIMES BE LIMITED TO A MAXIMUM OF FIFTY US DOLLARS. THE EXISTENCE OF MORE THAN ONE CLAIM WILL NOT ENLARGE THIS LIMIT. YOU AGREE THAT OUR SUPPLIERS WILL HAVE NO LIABILITY OF ANY KIND ARISING FROM OR RELATING TO THESE TERMS. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OR EXCLUSION OF LIABILITY FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR EXCLUSION MAY NOT APPLY TO YOU. 7. **Term and Termination.** Subject to this Section, these Terms will remain in full force and effect while you use the Site. We may suspend or terminate your rights to use the Site (including your Account) at any time for any reason at our sole discretion, including for any use of the Site in violation of these Terms. Upon termination of your rights under these Terms, your Account and right to access and use the Site will terminate immediately. Company will not have any liability whatsoever to you for any termination of your rights under these Terms, including for termination of your Account. Even after your rights under these Terms are terminated, the following provisions of these Terms will remain in effect: Sections 2.2 through 2.6 and Sections 3 through 8. 8. **General** 8.1. **Changes.** These Terms are subject to occasional revision, and if we make any substantial changes, we may notify you by sending you an e-mail to the last e-mail address you provided to us (if any), and/or by prominently posting notice of the changes on our Site. You are responsible for providing us with your most current e-mail address. In the event that the last e-mail address that you have provided us is not valid, or for any reason is not capable of delivering to you the notice described above, our dispatch of the e-mail containing such notice will nonetheless constitute effective notice of the changes described in the notice. Continued use of our Site following notice of such changes shall indicate your acknowledgement of such changes and agreement to be bound by the terms and conditions of such changes. 8.2. **Dispute Resolution.** Please read the following arbitration agreement in this Section (the "**Arbitration Agreement**") carefully.  It requires you to arbitrate disputes with Company, its parent companies, subsidiaries, affiliates, successors and assigns and all of their respective officers, directors, employees, agents, and representatives (collectively, the "**Company Parties**") and limits the manner in which you can seek relief from the Company Parties  (a) **Applicability of Arbitration Agreement** You agree that any dispute between you and any of the Company Parties relating in any way to the Site, the services offered on the Site (the "**Services**") or these Terms will be resolved by binding arbitration, rather than in court, except that (1) you and the Company Parties may assert individualized claims in small claims court if the claims qualify, remain in such court and advance solely on an individual, non-class basis; and (2) you or the Company Parties may seek equitable relief in court for infringement or other misuse of intellectual property rights (such as trademarks, trade dress, domain names, trade secrets, copyrights, and patents). **This Arbitration Agreement shall survive the expiration or termination of these Terms and shall apply, without limitation, to all claims that arose or were asserted before you agreed to these Terms (in accordance with the preamble) or any prior version of these Terms.** This Arbitration Agreement does not preclude you from bringing issues to the attention of federal, state or local agencies. Such agencies can, if the law allows, seek relief against the Company Parties on your behalf. For purposes of this Arbitration Agreement, "**Dispute**" will also include disputes that arose or involve facts occurring before the existence of this or any prior versions of the Agreement as well as claims that may arise after the termination of these Terms. (b) **Informal Dispute Resolution.** There might be instances when a Dispute arises between you and Company. If that occurs, Company is committed to working with you to reach a reasonable resolution. You and Company agree that good faith informal efforts to resolve Disputes can result in a prompt, low‐cost and mutually beneficial outcome. You and Company therefore agree that before either party commences arbitration against the other (or initiates an action in small claims court if a party so elects), we will personally meet and confer telephonically or via videoconference, in a good faith effort to resolve informally any Dispute covered by this Arbitration Agreement ("**Informal Dispute Resolution Conference**"). If you are represented by counsel, your counsel may participate in the conference, but you will also participate in the conference. The party initiating a Dispute must give notice to the other party in writing of its intent to initiate an Informal Dispute Resolution Conference ("**Notice**"), which shall occur within 45 days after the other party receives such Notice, unless an extension is mutually agreed upon by the parties. Notice to Company that you intend to initiate an Informal Dispute Resolution Conference should be sent by email to: [[email protected]](mailto:[email protected]), or by regular mail to 2261 Market Street #5686 San Francisco, CA 94114. The Notice must include: (1) your name, telephone number, mailing address, e‐mail address associated with your account (if you have one); (2) the name, telephone number, mailing address and e‐mail address of your counsel, if any; and (3) a description of your Dispute. The Informal Dispute Resolution Conference shall be individualized such that a separate conference must be held each time either party initiates a Dispute, even if the same law firm or group of law firms represents multiple users in similar cases, unless all parties agree; multiple individuals initiating a Dispute cannot participate in the same Informal Dispute Resolution Conference unless all parties agree. In the time between a party receiving the Notice and the Informal Dispute Resolution Conference, nothing in this Arbitration Agreement shall prohibit the parties from engaging in informal communications to resolve the initiating party's Dispute. Engaging in the Informal Dispute Resolution Conference is a condition precedent and requirement that must be fulfilled before commencing arbitration. The statute of limitations and any filing fee deadlines shall be tolled while the parties engage in the Informal Dispute Resolution Conference process required by this section. (c) **Arbitration Rules and Forum.** These Terms evidence a transaction involving interstate commerce; and notwithstanding any other provision herein with respect to the applicable substantive law, the Federal Arbitration Act, 9 U.S.C. § 1 et seq., will govern the interpretation and enforcement of this Arbitration Agreement and any arbitration proceedings. If the Informal Dispute Resolution Process described above does not resolve satisfactorily within 60 days after receipt of your Notice, you and Company agree that either party shall have the right to finally resolve the Dispute through binding arbitration. The Federal Arbitration Act governs the interpretation and enforcement of this Arbitration Agreement. The arbitration will be conducted by JAMS, an established alternative dispute resolution provider. Disputes involving claims and counterclaims with an amount in controversy under \$250,000, not inclusive of attorneys' fees and interest, shall be subject to JAMS' most current version of the Streamlined Arbitration Rules and procedures available at [http://www.jamsadr.com/rules-streamlined-arbitration/](http://www.jamsadr.com/rules-streamlined-arbitration/); all other claims shall be subject to JAMS's most current version of the Comprehensive Arbitration Rules and Procedures, available at [http://www.jamsadr.com/rules-comprehensive-arbitration/](http://www.jamsadr.com/rules-comprehensive-arbitration/). JAMS's rules are also available at [www.jamsadr.com](http://www.jamsadr.com) or by calling JAMS at 800-352-5267. A party who wishes to initiate arbitration must provide the other party with a request for arbitration (the "**Request**"). The Request must include: (1) the name, telephone number, mailing address, e‐mail address of the party seeking arbitration and the account username (if applicable) as well as the email address associated with any applicable account; (2) a statement of the legal claims being asserted and the factual bases of those claims; (3) a description of the remedy sought and an accurate, good‐faith calculation of the amount in controversy in United States Dollars; (4) a statement certifying completion of the Informal Dispute Resolution process as described above; and (5) evidence that the requesting party has paid any necessary filing fees in connection with such arbitration. If the party requesting arbitration is represented by counsel, the Request shall also include counsel's name, telephone number, mailing address, and email address. Such counsel must also sign the Request. By signing the Request, counsel certifies to the best of counsel's knowledge, information, and belief, formed after an inquiry reasonable under the circumstances, that: (1) the Request is not being presented for any improper purpose, such as to harass, cause unnecessary delay, or needlessly increase the cost of dispute resolution; (2) the claims, defenses and other legal contentions are warranted by existing law or by a nonfrivolous argument for extending, modifying, or reversing existing law or for establishing new law; and (3) the factual and damages contentions have evidentiary support or, if specifically so identified, will likely have evidentiary support after a reasonable opportunity for further investigation or discovery. Unless you and Company otherwise agree, or the Batch Arbitration process discussed in Subsection 8.2(h) is triggered, the arbitration will be conducted in the county where you reside. Subject to the JAMS Rules, the arbitrator may direct a limited and reasonable exchange of information between the parties, consistent with the expedited nature of the arbitration. If the JAMS is not available to arbitrate, the parties will select an alternative arbitral forum. Your responsibility to pay any JAMS fees and costs will be solely as set forth in the applicable JAMS Rules. You and Company agree that all materials and documents exchanged during the arbitration proceedings shall be kept confidential and shall not be shared with anyone except the parties' attorneys, accountants, or business advisors, and then subject to the condition that they agree to keep all materials and documents exchanged during the arbitration proceedings confidential. (d) **Authority of Arbitrator.** The arbitrator shall have exclusive authority to resolve all disputes subject to arbitration hereunder including, without limitation, any dispute related to the interpretation, applicability, enforceability or formation of this Arbitration Agreement or any portion of the Arbitration Agreement, except for the following: (1) all Disputes arising out of or relating to the subsection entitled "Waiver of Class or Other Non-Individualized Relief," including any claim that all or part of the subsection entitled "Waiver of Class or Other Non-Individualized Relief" is unenforceable, illegal, void or voidable, or that such subsection entitled "Waiver of Class or Other Non-Individualized Relief" has been breached, shall be decided by a court of competent jurisdiction and not by an arbitrator; (2) except as expressly contemplated in the subsection entitled "Batch Arbitration," all Disputes about the payment of arbitration fees shall be decided only by a court of competent jurisdiction and not by an arbitrator; (3) all Disputes about whether either party has satisfied any condition precedent to arbitration shall be decided only by a court of competent jurisdiction and not by an arbitrator; and (4) all Disputes about which version of the Arbitration Agreement applies shall be decided only by a court of competent jurisdiction and not by an arbitrator. The arbitration proceeding will not be consolidated with any other matters or joined with any other cases or parties, except as expressly provided in the subsection entitled "Batch Arbitration." The arbitrator shall have the authority to grant motions dispositive of all or part of any claim or dispute. The arbitrator shall have the authority to award monetary damages and to grant any non-monetary remedy or relief available to an individual party under applicable law, the arbitral forum's rules, and these Terms (including the Arbitration Agreement). The arbitrator shall issue a written award and statement of decision describing the essential findings and conclusions on which any award (or decision not to render an award) is based, including the calculation of any damages awarded. The arbitrator shall follow the applicable law. The award of the arbitrator is final and binding upon you and us. Judgment on the arbitration award may be entered in any court having jurisdiction. (e) **Waiver of Jury Trial.** EXCEPT AS SPECIFIED in section 8.2(a) YOU AND THE COMPANY PARTIES HEREBY WAIVE ANY CONSTITUTIONAL AND STATUTORY RIGHTS TO SUE IN COURT AND HAVE A TRIAL IN FRONT OF A JUDGE OR A JURY. You and the Company Parties are instead electing that all covered claims and disputes shall be resolved exclusively by arbitration under this Arbitration Agreement, except as specified in Section 8.2(a) above. An arbitrator can award on an individual basis the same damages and relief as a court and must follow these Terms as a court would. However, there is no judge or jury in arbitration, and court review of an arbitration award is subject to very limited review.  (f) **Waiver of Class or Other Non-Individualized Relief.**  YOU AND COMPANY AGREE THAT, EXCEPT AS SPECIFIED IN SUBSECTION 8.2(h) EACH OF US MAY BRING CLAIMS AGAINST THE OTHER ONLY ON AN INDIVIDUAL BASIS AND NOT ON A CLASS, REPRESENTATIVE, OR COLLECTIVE BASIS, AND THE PARTIES HEREBY WAIVE ALL RIGHTS TO HAVE ANY DISPUTE BE BROUGHT, HEARD, ADMINISTERED, RESOLVED, OR ARBITRATED ON A CLASS, COLLECTIVE, REPRESENTATIVE, OR MASS ACTION BASIS. ONLY INDIVIDUAL RELIEF IS AVAILABLE, AND DISPUTES OF MORE THAN ONE CUSTOMER OR USER CANNOT BE ARBITRATED OR CONSOLIDATED WITH THOSE OF ANY OTHER CUSTOMER OR USER. Subject to this Arbitration Agreement, the arbitrator may award declaratory or injunctive relief only in favor of the individual party seeking relief and only to the extent necessary to provide relief warranted by the party's individual claim. Nothing in this paragraph is intended to, nor shall it, affect the terms and conditions under the Subsection 8.2(h) entitled "Batch Arbitration." Notwithstanding anything to the contrary in this Arbitration Agreement, if a court decides by means of a final decision, not subject to any further appeal or recourse, that the limitations of this subsection, "Waiver of Class or Other Non-Individualized Relief," are invalid or unenforceable as to a particular claim or request for relief (such as a request for public injunctive relief), you and Company agree that that particular claim or request for relief (and only that particular claim or request for relief) shall be severed from the arbitration and may be litigated in the state or federal courts located in the State of California. All other Disputes shall be arbitrated or litigated in small claims court. This subsection does not prevent you or Company from participating in a class-wide settlement of claims. (g) **Attorneys' Fees and Costs.** The parties shall bear their own attorneys' fees and costs in arbitration unless the arbitrator finds that either the substance of the Dispute or the relief sought in the Request was frivolous or was brought for an improper purpose (as measured by the standards set forth in Federal Rule of Civil Procedure 11(b)). If you or Company need to invoke the authority of a court of competent jurisdiction to compel arbitration, then the party that obtains an order compelling arbitration in such action shall have the right to collect from the other party its reasonable costs, necessary disbursements, and reasonable attorneys' fees incurred in securing an order compelling arbitration. The prevailing party in any court action relating to whether either party has satisfied any condition precedent to arbitration, including the Informal Dispute Resolution Process, is entitled to recover their reasonable costs, necessary disbursements, and reasonable attorneys' fees and costs. (h) **Batch Arbitration.** To increase the efficiency of administration and resolution of arbitrations, you and Company agree that in the event that there are 100 or more individual Requests of a substantially similar nature filed against Company by or with the assistance of the same law firm, group of law firms, or organizations, within a 30 day period (or as soon as possible thereafter), the JAMS shall (1) administer the arbitration demands in batches of 100 Requests per batch (plus, to the extent there are less than 100 Requests left over after the batching described above, a final batch consisting of the remaining Requests); (2) appoint one arbitrator for each batch; and (3) provide for the resolution of each batch as a single consolidated arbitration with one set of filing and administrative fees due per side per batch, one procedural calendar, one hearing (if any) in a place to be determined by the arbitrator, and one final award ("**Batch Arbitration**"). All parties agree that Requests are of a "substantially similar nature" if they arise out of or relate to the same event or factual scenario and raise the same or similar legal issues and seek the same or similar relief. To the extent the parties disagree on the application of the Batch Arbitration process, the disagreeing party shall advise the JAMS, and the JAMS shall appoint a sole standing arbitrator to determine the applicability of the Batch Arbitration process ("**Administrative Arbitrator**"). In an effort to expedite resolution of any such dispute by the Administrative Arbitrator, the parties agree the Administrative Arbitrator may set forth such procedures as are necessary to resolve any disputes promptly. The Administrative Arbitrator's fees shall be paid by Company. You and Company agree to cooperate in good faith with the JAMS to implement the Batch Arbitration process including the payment of single filing and administrative fees for batches of Requests, as well as any steps to minimize the time and costs of arbitration, which may include: (1) the appointment of a discovery special master to assist the arbitrator in the resolution of discovery disputes; and (2) the adoption of an expedited calendar of the arbitration proceedings. This Batch Arbitration provision shall in no way be interpreted as authorizing a class, collective and/or mass arbitration or action of any kind, or arbitration involving joint or consolidated claims under any circumstances, except as expressly set forth in this provision. (i) **30-Day Right to Opt Out.**  You have the right to opt out of the provisions of this Arbitration Agreement by sending a timely written notice of your decision to opt out to the following address: 2261 Market Street #5686, San Francisco, CA 94114, or email to [[email protected]](mailto:[email protected]), within 30 days after first becoming subject to this Arbitration Agreement. Your notice must include your name and address and a clear statement that you want to opt out of this Arbitration Agreement. If you opt out of this Arbitration Agreement, all other parts of these Terms will continue to apply to you. Opting out of this Arbitration Agreement has no effect on any other arbitration agreements that you may currently have with us, or may enter into in the future with us. (j) **Invalidity, Expiration.** Except as provided in the subsection entitled "Waiver of Class or Other Non-Individualized Relief", if any part or parts of this Arbitration Agreement are found under the law to be invalid or unenforceable, then such specific part or parts shall be of no force and effect and shall be severed and the remainder of the Arbitration Agreement shall continue in full force and effect. You further agree that any Dispute that you have with Company as detailed in this Arbitration Agreement must be initiated via arbitration within the applicable statute of limitation for that claim or controversy, or it will be forever time barred. Likewise, you agree that all applicable statutes of limitation will apply to such arbitration in the same manner as those statutes of limitation would apply in the applicable court of competent jurisdiction. (k)**Modification.** Notwithstanding any provision in these Terms to the contrary, we agree that if Company makes any future material change to this Arbitration Agreement, you may reject that change within 30 days of such change becoming effective by writing Company at the following address: 2261 Market Street #5686, San Francisco, CA 94114, or email to [[email protected]](mailto:[email protected]). Unless you reject the change within 30 days of such change becoming effective by writing to Company in accordance with the foregoing, your continued use of the Site and/or Services, including the acceptance of products and services offered on the Site following the posting of changes to this Arbitration Agreement constitutes your acceptance of any such changes. Changes to this Arbitration Agreement do not provide you with a new opportunity to opt out of the Arbitration Agreement if you have previously agreed to a version of these Terms and did not validly opt out of arbitration. If you reject any change or update to this Arbitration Agreement, and you were bound by an existing agreement to arbitrate Disputes arising out of or relating in any way to your access to or use of the Services or of the Site, any communications you receive, any products sold or distributed through the Site, the Services, or these Terms, the provisions of this Arbitration Agreement as of the date you first accepted these Terms (or accepted any subsequent changes to these Terms) remain in full force and effect. Company will continue to honor any valid opt outs of the Arbitration Agreement that you made to a prior version of these Terms.  8.3. **Export.** The Site may be subject to U.S. export control laws and may be subject to export or import regulations in other countries. You agree not to export, reexport, or transfer, directly or indirectly, any U.S. technical data acquired from Company, or any products utilizing such data, in violation of the United States export laws or regulations. 8.4. **Disclosures.** Company is located at the address in Section 8.8. If you are a California resident, you may report complaints to the Complaint Assistance Unit of the Division of Consumer Product of the California Department of Consumer Affairs by contacting them in writing at 400 R Street, Sacramento, CA 95814, or by telephone at (800) 952-5210. 9.5. **Electronic Communications.** The communications between you and Company use electronic means, whether you use the Site or send us emails, or whether Company posts notices on the Site or communicates with you via email. For contractual purposes, you (a) consent to receive communications from Company in an electronic form; and (b) agree that all terms and conditions, agreements, notices, disclosures, and other communications that Company provides to you electronically satisfy any legal requirement that such communications would satisfy if it were be in a hardcopy writing. The foregoing does not affect your non-waivable rights. 8.6. **Entire Terms.** These Terms constitute the entire agreement between you and us regarding the use of the Site. Our failure to exercise or enforce any right or provision of these Terms shall not operate as a waiver of such right or provision. The section titles in these Terms are for convenience only and have no legal or contractual effect. The word "including" means "including without limitation". If any provision of these Terms is, for any reason, held to be invalid or unenforceable, the other provisions of these Terms will be unimpaired and the invalid or unenforceable provision will be deemed modified so that it is valid and enforceable to the maximum extent permitted by law. Your relationship to Company is that of an independent contractor, and neither party is an agent or partner of the other. These Terms, and your rights and obligations herein, may not be assigned, subcontracted, delegated, or otherwise transferred by you without Company's prior written consent, and any attempted assignment, subcontract, delegation, or transfer in violation of the foregoing will be null and void. Company may freely assign these Terms. The terms and conditions set forth in these Terms shall be binding upon assignees. 8.7. **Copyright/Trademark Information**. Copyright ©2024 Zep Software, Inc. All rights reserved. All trademarks, logos and service marks ("**Marks**") displayed on the Site are our property or the property of other third parties. You are not permitted to use these Marks without our prior written consent or the consent of such third party which may own the Marks. **Contact Information:** Daniel Chalef Address: 2261 Market Street \#5686 San Francisco, CA 94114 # Get threads ```http GET https://api.getzep.com/api/v2/threads ``` Returns all threads. ## Query Parameters - page_number (optional): Page number for pagination, starting from 1 - page_size (optional): Number of threads to retrieve per page. - order_by (optional): Field to order the results by: created_at, updated_at, user_id, thread_id. - asc (optional): Order direction: true for ascending, false for descending. ## Response Body - 200: List of threads - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.list_all() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.listAll(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.ListAll( context.TODO(), &v2.ThreadListAllRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " \ -d page_number=0 \ -d page_size=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.list_all() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.listAll(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.ListAll( context.TODO(), &v2.ThreadListAllRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " \ -d page_number=0 \ -d page_size=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.list_all() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.listAll(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.ListAll( context.TODO(), &v2.ThreadListAllRequest{}, ) ``` # Start a new thread. ```http POST https://api.getzep.com/api/v2/threads Content-Type: application/json ``` Start a new thread. ## Response Body - 201: The thread object. - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "thread_id": "thread_id", "user_id": "user_id" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.create( thread_id="thread_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.create({ threadId: "thread_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Create( context.TODO(), &v2.CreateThreadRequest{ ThreadID: "thread_id", UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "thread_id": "string", "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.create( thread_id="thread_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.create({ threadId: "thread_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Create( context.TODO(), &v2.CreateThreadRequest{ ThreadID: "thread_id", UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/threads \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "thread_id": "string", "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.create( thread_id="thread_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.create({ threadId: "thread_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Create( context.TODO(), &v2.CreateThreadRequest{ ThreadID: "thread_id", UserID: "user_id", }, ) ``` # Delete thread ```http DELETE https://api.getzep.com/api/v2/threads/{threadId} ``` Deletes a thread. ## Path Parameters - threadId (required): The ID of the thread for which memory should be deleted. ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/threads/threadId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.delete( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.delete("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Delete( context.TODO(), "threadId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/threads/:threadId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.delete( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.delete("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Delete( context.TODO(), "threadId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/threads/:threadId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.delete( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.delete("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Delete( context.TODO(), "threadId", ) ``` # Get thread memory context ```http GET https://api.getzep.com/api/v2/threads/{threadId}/context ``` Returns most relevant context for a given thread. ## Path Parameters - threadId (required): The ID of the thread for which to retrieve context. ## Query Parameters - lastn (optional): The number of most recent memory entries to retrieve. - minRating (optional): The minimum rating by which to filter relevant facts. ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/threads/threadId/context \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get_user_context( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.getUserContext("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.GetUserContext( context.TODO(), "threadId", &v2.ThreadGetUserContextRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads/:threadId/context \ -H "Authorization: Api-Key " \ -d lastn=0 \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get_user_context( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.getUserContext("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.GetUserContext( context.TODO(), "threadId", &v2.ThreadGetUserContextRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads/:threadId/context \ -H "Authorization: Api-Key " \ -d lastn=0 \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get_user_context( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.getUserContext("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.GetUserContext( context.TODO(), "threadId", &v2.ThreadGetUserContextRequest{}, ) ``` # Get Messages for Thread ```http GET https://api.getzep.com/api/v2/threads/{threadId}/messages ``` Returns messages for a thread. ## Path Parameters - threadId (required): Thread ID ## Query Parameters - limit (optional): Limit the number of results returned - cursor (optional): Cursor for pagination ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/threads/threadId/messages ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.get("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Get( context.TODO(), "threadId", &v2.ThreadGetRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads/:threadId/messages \ -d limit=0 \ -d cursor=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.get("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Get( context.TODO(), "threadId", &v2.ThreadGetRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/threads/:threadId/messages \ -d limit=0 \ -d cursor=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.get( thread_id="threadId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.get("threadId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.Get( context.TODO(), "threadId", &v2.ThreadGetRequest{}, ) ``` # Add messages to a thread ```http POST https://api.getzep.com/api/v2/threads/{threadId}/messages Content-Type: application/json ``` Add messages to a thread. ## Path Parameters - threadId (required): The ID of the thread to which messages should be added. ## Response Body - 200: An object, optionally containing user context retrieved for the last thread message - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/threads/threadId/messages \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "content": "content", "role_type": "norole" } ] }' ``` ```python from zep_cloud import Message from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.add_messages( thread_id="threadId", messages=[ Message( content="content", role_type="norole", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.addMessages("threadId", { messages: [{ content: "content", roleType: "norole" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.AddMessages( context.TODO(), "threadId", &v2.AddThreadMessagesRequest{ Messages: []*v2.Message{ &v2.Message{ Content: "content", RoleType: v2.RoleTypeNoRole, }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/threads/:threadId/messages \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "content": "string", "role_type": "norole" } ] }' ``` ```python from zep_cloud import Message from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.thread.add_messages( thread_id="threadId", messages=[ Message( content="content", role_type="norole", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.thread.addMessages("threadId", { messages: [{ content: "content", roleType: "norole" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Thread.AddMessages( context.TODO(), "threadId", &v2.AddThreadMessagesRequest{ Messages: []*v2.Message{ &v2.Message{ Content: "content", RoleType: v2.RoleTypeNoRole, }, }, }, ) ``` # Add User ```http POST https://api.getzep.com/api/v2/users Content-Type: application/json ``` Adds a user. ## Response Body - 201: The user that was added. - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/users \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "user_id": "user_id" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.add( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.add({ userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Add( context.TODO(), &v2.CreateUserRequest{ UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/users \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.add( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.add({ userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Add( context.TODO(), &v2.CreateUserRequest{ UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/users \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.add( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.add({ userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Add( context.TODO(), &v2.CreateUserRequest{ UserID: "user_id", }, ) ``` # Get Users ```http GET https://api.getzep.com/api/v2/users-ordered ``` Returns all users. ## Query Parameters - pageNumber (optional): Page number for pagination, starting from 1 - pageSize (optional): Number of users to retrieve per page ## Response Body - 200: Successfully retrieved list of users - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/users-ordered \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.list_ordered() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.listOrdered(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.ListOrdered( context.TODO(), &v2.UserListOrderedRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/users-ordered \ -H "Authorization: Api-Key " \ -d pageNumber=0 \ -d pageSize=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.list_ordered() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.listOrdered(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.ListOrdered( context.TODO(), &v2.UserListOrderedRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/users-ordered \ -H "Authorization: Api-Key " \ -d pageNumber=0 \ -d pageSize=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.list_ordered() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.listOrdered(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.ListOrdered( context.TODO(), &v2.UserListOrderedRequest{}, ) ``` # Get User ```http GET https://api.getzep.com/api/v2/users/{userId} ``` Returns a user. ## Path Parameters - userId (required): The user_id of the user to get. ## Response Body - 200: The user that was retrieved. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/users/userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.get("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Get( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.get("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Get( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.get("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Get( context.TODO(), "userId", ) ``` # Delete User ```http DELETE https://api.getzep.com/api/v2/users/{userId} ``` Deletes a user. ## Path Parameters - userId (required): User ID ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/users/userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.delete( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.delete("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Delete( context.TODO(), "userId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.delete( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.delete("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Delete( context.TODO(), "userId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.delete( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.delete("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Delete( context.TODO(), "userId", ) ``` # Update User ```http PATCH https://api.getzep.com/api/v2/users/{userId} Content-Type: application/json ``` Updates a user. ## Path Parameters - userId (required): User ID ## Response Body - 200: The user that was updated. - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/users/userId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.update( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.update("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Update( context.TODO(), "userId", &v2.UpdateUserRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.update( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.update("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Update( context.TODO(), "userId", &v2.UpdateUserRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.update( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.update("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Update( context.TODO(), "userId", &v2.UpdateUserRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/users/:userId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.update( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.update("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.Update( context.TODO(), "userId", &v2.UpdateUserRequest{}, ) ``` # Get User Node ```http GET https://api.getzep.com/api/v2/users/{userId}/node ``` Returns a user's node. ## Path Parameters - userId (required): The user_id of the user to get the node for. ## Response Body - 200: Response object containing the User node. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/users/userId/node \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_node( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getNode("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetNode( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId/node \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_node( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getNode("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetNode( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId/node \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_node( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getNode("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetNode( context.TODO(), "userId", ) ``` # Get User Sessions ```http GET https://api.getzep.com/api/v2/users/{userId}/sessions ``` Returns all sessions for a user. ## Path Parameters - userId (required): User ID ## Response Body - 200: OK - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/users/userId/sessions \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_sessions( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getSessions("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetSessions( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId/sessions \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_sessions( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getSessions("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetSessions( context.TODO(), "userId", ) ``` # Create Group ```http POST https://api.getzep.com/api/v2/groups Content-Type: application/json ``` Creates a new group. ## Response Body - 201: The added group - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/groups \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "group_id": "group_id" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.add( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.add({ groupId: "group_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Add( context.TODO(), &v2.CreateGroupRequest{ GroupID: "group_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/groups \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "group_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.add( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.add({ groupId: "group_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Add( context.TODO(), &v2.CreateGroupRequest{ GroupID: "group_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/groups \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "group_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.add( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.add({ groupId: "group_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Add( context.TODO(), &v2.CreateGroupRequest{ GroupID: "group_id", }, ) ``` # Get All Groups ```http GET https://api.getzep.com/api/v2/groups-ordered ``` Returns all groups. ## Query Parameters - pageNumber (optional): Page number for pagination, starting from 1. - pageSize (optional): Number of groups to retrieve per page. ## Response Body - 200: Successfully retrieved list of groups. - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/groups-ordered \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_all_groups() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getAllGroups(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetAllGroups( context.TODO(), &v2.GetGroupsOrderedRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/groups-ordered \ -H "Authorization: Api-Key " \ -d pageNumber=0 \ -d pageSize=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_all_groups() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getAllGroups(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetAllGroups( context.TODO(), &v2.GetGroupsOrderedRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/groups-ordered \ -H "Authorization: Api-Key " \ -d pageNumber=0 \ -d pageSize=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_all_groups() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getAllGroups(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetAllGroups( context.TODO(), &v2.GetGroupsOrderedRequest{}, ) ``` # Get Group ```http GET https://api.getzep.com/api/v2/groups/{groupId} ``` Returns a group. ## Path Parameters - groupId (required): The group_id of the group to get. ## Response Body - 200: The group that was retrieved. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/groups/groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_group( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getGroup("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetGroup( context.TODO(), "groupId", ) ``` ```shell curl https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_group( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getGroup("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetGroup( context.TODO(), "groupId", ) ``` ```shell curl https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_group( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getGroup("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetGroup( context.TODO(), "groupId", ) ``` # Delete Group ```http DELETE https://api.getzep.com/api/v2/groups/{groupId} ``` Deletes a group. ## Path Parameters - groupId (required): Group ID ## Response Body - 200: Deleted - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/groups/groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.delete( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.delete("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Delete( context.TODO(), "groupId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.delete( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.delete("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Delete( context.TODO(), "groupId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.delete( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.delete("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Delete( context.TODO(), "groupId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.delete( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.delete("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Delete( context.TODO(), "groupId", ) ``` # Update Group ```http PATCH https://api.getzep.com/api/v2/groups/{groupId} Content-Type: application/json ``` Updates information about a group. ## Path Parameters - groupId (required): Group ID ## Response Body - 201: The added group - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/groups/groupId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.update( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.update("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Update( context.TODO(), "groupId", &v2.UpdateGroupRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.update( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.update("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Update( context.TODO(), "groupId", &v2.UpdateGroupRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.update( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.update("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Update( context.TODO(), "groupId", &v2.UpdateGroupRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/groups/:groupId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.update( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.update("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.Update( context.TODO(), "groupId", &v2.UpdateGroupRequest{}, ) ``` # Get Entity Types ```http GET https://api.getzep.com/api/v2/entity-types ``` Returns all entity types for a project. ## Response Body - 200: The list of entity types. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.list_entity_types() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.listEntityTypes(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.ListEntityTypes( context.TODO(), ) ``` ```shell curl https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.list_entity_types() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.listEntityTypes(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.ListEntityTypes( context.TODO(), ) ``` ```shell curl https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.list_entity_types() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.listEntityTypes(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.ListEntityTypes( context.TODO(), ) ``` # Set Entity Types ```http PUT https://api.getzep.com/api/v2/entity-types Content-Type: application/json ``` Sets the entity types for a project, replacing any existing ones. ## Response Body - 200: Entity types set successfully - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X PUT https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.set_entity_types_internal() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.setEntityTypesInternal(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.SetEntityTypesInternal( context.TODO(), &v2.EntityTypeRequest{}, ) ``` ```shell curl -X PUT https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.set_entity_types_internal() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.setEntityTypesInternal(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.SetEntityTypesInternal( context.TODO(), &v2.EntityTypeRequest{}, ) ``` ```shell curl -X PUT https://api.getzep.com/api/v2/entity-types \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.set_entity_types_internal() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.setEntityTypesInternal(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.SetEntityTypesInternal( context.TODO(), &v2.EntityTypeRequest{}, ) ``` # Add Data ```http POST https://api.getzep.com/api/v2/graph Content-Type: application/json ``` Add data to the graph. ## Response Body - 202: Added episode - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph \ -H "Content-Type: application/json" \ -d '{ "data": "data", "type": "text" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add( data="data", type="text", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.add({ data: "data", type: "text" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Add( context.TODO(), &v2.AddDataRequest{ Data: "data", Type: v2.GraphDataTypeText, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph \ -H "Content-Type: application/json" \ -d '{ "data": "string", "type": "text" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add( data="data", type="text", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.add({ data: "data", type: "text" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Add( context.TODO(), &v2.AddDataRequest{ Data: "data", Type: v2.GraphDataTypeText, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph \ -H "Content-Type: application/json" \ -d '{ "data": "string", "type": "text" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add( data="data", type="text", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.add({ data: "data", type: "text" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Add( context.TODO(), &v2.AddDataRequest{ Data: "data", Type: v2.GraphDataTypeText, }, ) ``` # Add Data in batch mode ```http POST https://api.getzep.com/api/v2/graph-batch Content-Type: application/json ``` Add data to the graph in batch mode, processing episodes concurrently. Use only for data that is insensitive to processing order. ## Response Body - 202: Added episodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph-batch \ -H "Content-Type: application/json" \ -d '{ "episodes": [ { "data": "data", "type": "text" } ] }' ``` ```python from zep_cloud import EpisodeData from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_batch( episodes=[ EpisodeData( data="data", type="text", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addBatch({ episodes: [{ data: "data", type: "text" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddBatch( context.TODO(), &v2.AddDataBatchRequest{ Episodes: []*v2.EpisodeData{ &v2.EpisodeData{ Data: "data", Type: v2.GraphDataTypeText, }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph-batch \ -H "Content-Type: application/json" \ -d '{ "episodes": [ { "data": "string", "type": "text" } ] }' ``` ```python from zep_cloud import EpisodeData from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_batch( episodes=[ EpisodeData( data="data", type="text", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addBatch({ episodes: [{ data: "data", type: "text" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddBatch( context.TODO(), &v2.AddDataBatchRequest{ Episodes: []*v2.EpisodeData{ &v2.EpisodeData{ Data: "data", Type: v2.GraphDataTypeText, }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph-batch \ -H "Content-Type: application/json" \ -d '{ "episodes": [ { "data": "string", "type": "text" } ] }' ``` ```python from zep_cloud import EpisodeData from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_batch( episodes=[ EpisodeData( data="data", type="text", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addBatch({ episodes: [{ data: "data", type: "text" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddBatch( context.TODO(), &v2.AddDataBatchRequest{ Episodes: []*v2.EpisodeData{ &v2.EpisodeData{ Data: "data", Type: v2.GraphDataTypeText, }, }, }, ) ``` # Add Fact Triple ```http POST https://api.getzep.com/api/v2/graph/add-fact-triple Content-Type: application/json ``` Add a fact triple for a user or group ## Response Body - 200: Resulting triple - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/add-fact-triple \ -H "Content-Type: application/json" \ -d '{ "fact": "fact", "fact_name": "fact_name", "target_node_name": "target_node_name" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_fact_triple( fact="fact", fact_name="fact_name", target_node_name="target_node_name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addFactTriple({ fact: "fact", factName: "fact_name", targetNodeName: "target_node_name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddFactTriple( context.TODO(), &v2.AddTripleRequest{ Fact: "fact", FactName: "fact_name", TargetNodeName: "target_node_name", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/add-fact-triple \ -H "Content-Type: application/json" \ -d '{ "fact": "string", "fact_name": "string", "target_node_name": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_fact_triple( fact="fact", fact_name="fact_name", target_node_name="target_node_name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addFactTriple({ fact: "fact", factName: "fact_name", targetNodeName: "target_node_name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddFactTriple( context.TODO(), &v2.AddTripleRequest{ Fact: "fact", FactName: "fact_name", TargetNodeName: "target_node_name", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/add-fact-triple \ -H "Content-Type: application/json" \ -d '{ "fact": "string", "fact_name": "string", "target_node_name": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.add_fact_triple( fact="fact", fact_name="fact_name", target_node_name="target_node_name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.addFactTriple({ fact: "fact", factName: "fact_name", targetNodeName: "target_node_name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.AddFactTriple( context.TODO(), &v2.AddTripleRequest{ Fact: "fact", FactName: "fact_name", TargetNodeName: "target_node_name", }, ) ``` # Clone graph ```http POST https://api.getzep.com/api/v2/graph/clone Content-Type: application/json ``` Clone a user or group graph. ## Response Body - 202: Response object containing group_id or user_id pointing to the new graph - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/clone \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.clone() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.clone(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Clone( context.TODO(), &v2.CloneGraphRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/clone \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.clone() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.clone(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Clone( context.TODO(), &v2.CloneGraphRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/clone \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.clone() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.clone(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Clone( context.TODO(), &v2.CloneGraphRequest{}, ) ``` # Search Graph ```http POST https://api.getzep.com/api/v2/graph/search Content-Type: application/json ``` Perform a graph search query. ## Response Body - 200: Graph search results - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/search \ -H "Content-Type: application/json" \ -d '{ "query": "query" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.search( query="query", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.search({ query: "query" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Search( context.TODO(), &v2.GraphSearchQuery{ Query: "query", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/search \ -H "Content-Type: application/json" \ -d '{ "query": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.search( query="query", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.search({ query: "query" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Search( context.TODO(), &v2.GraphSearchQuery{ Query: "query", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/search \ -H "Content-Type: application/json" \ -d '{ "query": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.search( query="query", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.search({ query: "query" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Search( context.TODO(), &v2.GraphSearchQuery{ Query: "query", }, ) ``` # Get Group Edges ```http POST https://api.getzep.com/api/v2/graph/edge/group/{group_id} Content-Type: application/json ``` Returns all edges for a group. ## Path Parameters - group_id (required): Group ID ## Response Body - 200: Edges - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/group/group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByGroupID( context.TODO(), "group_id", &v2.GraphEdgesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/group/:group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByGroupID( context.TODO(), "group_id", &v2.GraphEdgesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/group/:group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByGroupID( context.TODO(), "group_id", &v2.GraphEdgesRequest{}, ) ``` # Get User Edges ```http POST https://api.getzep.com/api/v2/graph/edge/user/{user_id} Content-Type: application/json ``` Returns all edges for a user. ## Path Parameters - user_id (required): User ID ## Response Body - 200: Edges - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/user/user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByUserID( context.TODO(), "user_id", &v2.GraphEdgesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/user/:user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByUserID( context.TODO(), "user_id", &v2.GraphEdgesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/edge/user/:user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.GetByUserID( context.TODO(), "user_id", &v2.GraphEdgesRequest{}, ) ``` # Get Edge ```http GET https://api.getzep.com/api/v2/graph/edge/{uuid} ``` Returns a specific edge by its UUID. ## Path Parameters - uuid (required): Edge UUID ## Response Body - 200: Edge - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/edge/uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/edge/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/edge/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/edge/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Get( context.TODO(), "uuid", ) ``` # Delete Edge ```http DELETE https://api.getzep.com/api/v2/graph/edge/{uuid} ``` Deletes an edge by UUID. ## Path Parameters - uuid (required): Edge UUID ## Response Body - 200: Edge deleted - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/edge/uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Delete( context.TODO(), "uuid", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/edge/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Delete( context.TODO(), "uuid", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/edge/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.edge.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.edge.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Edge.Delete( context.TODO(), "uuid", ) ``` # Get Group Episodes ```http GET https://api.getzep.com/api/v2/graph/episodes/group/{group_id} ``` Returns episodes by group id. ## Path Parameters - group_id (required): Group ID ## Query Parameters - lastn (optional): The number of most recent episodes to retrieve. ## Response Body - 200: Episodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/episodes/group/group_id ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByGroupId("group_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByGroupID( context.TODO(), "group_id", &graph.EpisodeGetByGroupIDRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/graph/episodes/group/:group_id \ -d lastn=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByGroupId("group_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByGroupID( context.TODO(), "group_id", &graph.EpisodeGetByGroupIDRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/graph/episodes/group/:group_id \ -d lastn=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByGroupId("group_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByGroupID( context.TODO(), "group_id", &graph.EpisodeGetByGroupIDRequest{}, ) ``` # Get User Episodes ```http GET https://api.getzep.com/api/v2/graph/episodes/user/{user_id} ``` Returns episodes by user id. ## Path Parameters - user_id (required): User ID ## Query Parameters - lastn (optional): The number of most recent episodes entries to retrieve. ## Response Body - 200: Episodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/episodes/user/user_id ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByUserId("user_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByUserID( context.TODO(), "user_id", &graph.EpisodeGetByUserIDRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/graph/episodes/user/:user_id \ -d lastn=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByUserId("user_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByUserID( context.TODO(), "user_id", &graph.EpisodeGetByUserIDRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/graph/episodes/user/:user_id \ -d lastn=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getByUserId("user_id"); ``` ```go import ( context "context" graph "github.com/getzep/zep-go/v2/graph" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetByUserID( context.TODO(), "user_id", &graph.EpisodeGetByUserIDRequest{}, ) ``` # Get Episode ```http GET https://api.getzep.com/api/v2/graph/episodes/{uuid} ``` Returns episodes by UUID ## Path Parameters - uuid (required): Episode UUID ## Response Body - 200: Episode - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/episodes/uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/episodes/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/episodes/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Get( context.TODO(), "uuid", ) ``` # Delete Episode ```http DELETE https://api.getzep.com/api/v2/graph/episodes/{uuid} ``` Deletes an episode by its UUID. ## Path Parameters - uuid (required): Episode UUID ## Response Body - 200: Episode deleted - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/episodes/uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Delete( context.TODO(), "uuid", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/episodes/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Delete( context.TODO(), "uuid", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/episodes/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Delete( context.TODO(), "uuid", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/graph/episodes/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.delete( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.delete("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.Delete( context.TODO(), "uuid", ) ``` # Return any nodes and edges mentioned in an episode ```http GET https://api.getzep.com/api/v2/graph/episodes/{uuid}/mentions ``` Returns nodes and edges mentioned in an episode ## Path Parameters - uuid (required): Episode uuid ## Response Body - 200: Edges and nodes mentioned in an episode - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/episodes/uuid/mentions ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_nodes_and_edges( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getNodesAndEdges("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetNodesAndEdges( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/episodes/:uuid/mentions ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_nodes_and_edges( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getNodesAndEdges("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetNodesAndEdges( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/episodes/:uuid/mentions ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.episode.get_nodes_and_edges( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.episode.getNodesAndEdges("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Episode.GetNodesAndEdges( context.TODO(), "uuid", ) ``` # Get Group Nodes ```http POST https://api.getzep.com/api/v2/graph/node/group/{group_id} Content-Type: application/json ``` Returns all nodes for a group. ## Path Parameters - group_id (required): Group ID ## Response Body - 200: Nodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/group/group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByGroupID( context.TODO(), "group_id", &v2.GraphNodesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/group/:group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByGroupID( context.TODO(), "group_id", &v2.GraphNodesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/group/:group_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_group_id( group_id="group_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByGroupId("group_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByGroupID( context.TODO(), "group_id", &v2.GraphNodesRequest{}, ) ``` # Get User Nodes ```http POST https://api.getzep.com/api/v2/graph/node/user/{user_id} Content-Type: application/json ``` Returns all nodes for a user ## Path Parameters - user_id (required): User ID ## Response Body - 200: Nodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/user/user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByUserID( context.TODO(), "user_id", &v2.GraphNodesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/user/:user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByUserID( context.TODO(), "user_id", &v2.GraphNodesRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/graph/node/user/:user_id \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_by_user_id( user_id="user_id", ) ``` ```typescript import { ZepClient, Zep } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getByUserId("user_id", {}); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetByUserID( context.TODO(), "user_id", &v2.GraphNodesRequest{}, ) ``` # Get Entity Edges for a node ```http GET https://api.getzep.com/api/v2/graph/node/{node_uuid}/entity-edges ``` Returns all edges for a node ## Path Parameters - node_uuid (required): Node UUID ## Response Body - 200: Edges - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/node/node_uuid/entity-edges ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_edges( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEdges("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEdges( context.TODO(), "node_uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:node_uuid/entity-edges ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_edges( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEdges("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEdges( context.TODO(), "node_uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:node_uuid/entity-edges ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_edges( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEdges("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEdges( context.TODO(), "node_uuid", ) ``` # Get Episodes for a node ```http GET https://api.getzep.com/api/v2/graph/node/{node_uuid}/episodes ``` Returns all episodes that mentioned a given node ## Path Parameters - node_uuid (required): Node UUID ## Response Body - 200: Episodes - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/node/node_uuid/episodes ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_episodes( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEpisodes("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEpisodes( context.TODO(), "node_uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:node_uuid/episodes ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_episodes( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEpisodes("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEpisodes( context.TODO(), "node_uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:node_uuid/episodes ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get_episodes( node_uuid="node_uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.getEpisodes("node_uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.GetEpisodes( context.TODO(), "node_uuid", ) ``` # Get Node ```http GET https://api.getzep.com/api/v2/graph/node/{uuid} ``` Returns a specific node by its UUID. ## Path Parameters - uuid (required): Node UUID ## Response Body - 200: Node - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/graph/node/uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.Get( context.TODO(), "uuid", ) ``` ```shell curl https://api.getzep.com/api/v2/graph/node/:uuid ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.graph.node.get( uuid_="uuid", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.graph.node.get("uuid"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Graph.Node.Get( context.TODO(), "uuid", ) ``` # Returns a fact by UUID ```http GET https://api.getzep.com/api/v2/facts/{factUUID} ``` Deprecated API: get fact by uuid ## Path Parameters - factUUID (required): Fact UUID ## Response Body - 200: The fact with the specified UUID. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/facts/factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetFact( context.TODO(), "factUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/facts/:factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetFact( context.TODO(), "factUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/facts/:factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetFact( context.TODO(), "factUUID", ) ``` # Delete a fact for the given UUID ```http DELETE https://api.getzep.com/api/v2/facts/{factUUID} ``` Deprecated API: delete a fact ## Path Parameters - factUUID (required): Fact UUID ## Response Body - 200: Deleted - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/facts/factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.deleteFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.DeleteFact( context.TODO(), "factUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/facts/:factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.deleteFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.DeleteFact( context.TODO(), "factUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/facts/:factUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete_fact( fact_uuid="factUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.deleteFact("factUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.DeleteFact( context.TODO(), "factUUID", ) ``` # Deprecated: Add Session ```http POST https://api.getzep.com/api/v2/sessions Content-Type: application/json ``` Deprecated: Creates a new session. Use thread.create instead. ## Response Body - 201: The added session. - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_id": "session_id", "user_id": "user_id" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session( session_id="session_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSession({ sessionId: "session_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSession( context.TODO(), &v2.CreateSessionRequest{ SessionID: "session_id", UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_id": "string", "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session( session_id="session_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSession({ sessionId: "session_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSession( context.TODO(), &v2.CreateSessionRequest{ SessionID: "session_id", UserID: "user_id", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_id": "string", "user_id": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session( session_id="session_id", user_id="user_id", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSession({ sessionId: "session_id", userId: "user_id" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSession( context.TODO(), &v2.CreateSessionRequest{ SessionID: "session_id", UserID: "user_id", }, ) ``` # Deprecated: Get Sessions ```http GET https://api.getzep.com/api/v2/sessions-ordered ``` Deprecated: Returns all sessions. Use GET /threads instead. ## Query Parameters - page_number (optional): Page number for pagination, starting from 1 - page_size (optional): Number of sessions to retrieve per page. - order_by (optional): Field to order the results by: created_at, updated_at, user_id, session_id. - asc (optional): Order direction: true for ascending, false for descending. ## Response Body - 200: List of sessions - 400: Bad Request - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions-ordered \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.list_sessions() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.listSessions(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ListSessions( context.TODO(), &v2.MemoryListSessionsRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions-ordered \ -H "Authorization: Api-Key " \ -d page_number=0 \ -d page_size=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.list_sessions() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.listSessions(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ListSessions( context.TODO(), &v2.MemoryListSessionsRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions-ordered \ -H "Authorization: Api-Key " \ -d page_number=0 \ -d page_size=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.list_sessions() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.listSessions(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ListSessions( context.TODO(), &v2.MemoryListSessionsRequest{}, ) ``` # End multiple sessions. ```http POST https://api.getzep.com/api/v2/sessions/end Content-Type: application/json ``` Deprecated API: End multiple sessions by their IDs. ## Response Body - 200: OK - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_ids": [ "session_ids" ] }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_sessions( session_ids=["session_ids"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSessions({ sessionIds: ["session_ids"] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSessions( context.TODO(), &v2.EndSessionsRequest{ SessionIDs: []string{ "session_ids", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_ids": [ "string" ] }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_sessions( session_ids=["session_ids"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSessions({ sessionIds: ["session_ids"] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSessions( context.TODO(), &v2.EndSessionsRequest{ SessionIDs: []string{ "session_ids", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_ids": [ "string" ] }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_sessions( session_ids=["session_ids"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSessions({ sessionIds: ["session_ids"] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSessions( context.TODO(), &v2.EndSessionsRequest{ SessionIDs: []string{ "session_ids", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "session_ids": [ "string" ] }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_sessions( session_ids=["session_ids"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSessions({ sessionIds: ["session_ids"] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSessions( context.TODO(), &v2.EndSessionsRequest{ SessionIDs: []string{ "session_ids", }, }, ) ``` # Search sessions for the specified query. ```http POST https://api.getzep.com/api/v2/sessions/search Content-Type: application/json ``` Deprecated API: Search sessions for the specified query. ## Query Parameters - limit (optional): The maximum number of search results to return. Defaults to None (no limit). ## Response Body - 200: A SessionSearchResponse object representing the search results. - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/search \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "text": "text" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.search_sessions( text="text", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.searchSessions({ text: "text" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.SearchSessions( context.TODO(), &v2.SessionSearchQuery{ Text: "text", }, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/sessions/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "text": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.search_sessions( text="text", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.searchSessions({ text: "text" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.SearchSessions( context.TODO(), &v2.SessionSearchQuery{ Text: "text", }, ) ``` # Get Session. Deprecated: use thread.get instead. ```http GET https://api.getzep.com/api/v2/sessions/{sessionId} ``` Returns a session. Deprecated: use thread.get instead. ## Path Parameters - sessionId (required): The unique identifier of the session. ## Response Body - 200: The session with the specified ID. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSession( context.TODO(), "sessionId", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSession( context.TODO(), "sessionId", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSession( context.TODO(), "sessionId", ) ``` # Update a session. Deprecated: No longer supported. ```http PATCH https://api.getzep.com/api/v2/sessions/{sessionId} Content-Type: application/json ``` Update Session Metadata. Deprecated: This endpoint is no longer supported and will be removed in a future release. ## Path Parameters - sessionId (required): The unique identifier of the session. ## Response Body - 200: The updated session. - 400: Bad Request - 404: Not Found - 409: Conflict - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/sessionId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "metadata": { "key": "value" } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_session( session_id="sessionId", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateSession("sessionId", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateSession( context.TODO(), "sessionId", &v2.UpdateSessionRequest{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_session( session_id="sessionId", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateSession("sessionId", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateSession( context.TODO(), "sessionId", &v2.UpdateSessionRequest{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_session( session_id="sessionId", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateSession("sessionId", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateSession( context.TODO(), "sessionId", &v2.UpdateSessionRequest{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_session( session_id="sessionId", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateSession("sessionId", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateSession( context.TODO(), "sessionId", &v2.UpdateSessionRequest{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_session( session_id="sessionId", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateSession("sessionId", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateSession( context.TODO(), "sessionId", &v2.UpdateSessionRequest{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` # Deprecated: Classify Session ```http POST https://api.getzep.com/api/v2/sessions/{sessionId}/classify Content-Type: application/json ``` Deprecated: Classifies a session. ## Path Parameters - sessionId (required): Session ID ## Response Body - 200: A response object containing the name and classification result. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/sessionId/classify \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "classes": [ "classes" ], "name": "name" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.classify_session( session_id="sessionId", classes=["classes"], name="name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.classifySession("sessionId", { classes: ["classes"], name: "name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ClassifySession( context.TODO(), "sessionId", &v2.ClassifySessionRequest{ Classes: []string{ "classes", }, Name: "name", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/classify \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "classes": [ "string" ], "name": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.classify_session( session_id="sessionId", classes=["classes"], name="name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.classifySession("sessionId", { classes: ["classes"], name: "name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ClassifySession( context.TODO(), "sessionId", &v2.ClassifySessionRequest{ Classes: []string{ "classes", }, Name: "name", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/classify \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "classes": [ "string" ], "name": "string" }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.classify_session( session_id="sessionId", classes=["classes"], name="name", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.classifySession("sessionId", { classes: ["classes"], name: "name" }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.ClassifySession( context.TODO(), "sessionId", &v2.ClassifySessionRequest{ Classes: []string{ "classes", }, Name: "name", }, ) ``` # End a session ```http POST https://api.getzep.com/api/v2/sessions/{sessionId}/end Content-Type: application/json ``` Deprecated API: End a session by ID. ## Path Parameters - sessionId (required): Session ID ## Response Body - 200: OK - 400: Bad Request - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/sessionId/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSession( context.TODO(), "sessionId", &v2.EndSessionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSession( context.TODO(), "sessionId", &v2.EndSessionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSession( context.TODO(), "sessionId", &v2.EndSessionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/end \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.end_session( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.endSession("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.EndSession( context.TODO(), "sessionId", &v2.EndSessionRequest{}, ) ``` # Returns all facts for a session by ID ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/facts ``` Deprecated API: get facts for a session ## Path Parameters - sessionId (required): Session ID ## Query Parameters - minRating (optional): Minimum rating by which to filter facts ## Response Body - 200: The facts for the session. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_facts( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionFacts("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionFacts( context.TODO(), "sessionId", &v2.MemoryGetSessionFactsRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/facts \ -H "Authorization: Api-Key " \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_facts( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionFacts("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionFacts( context.TODO(), "sessionId", &v2.MemoryGetSessionFactsRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/facts \ -H "Authorization: Api-Key " \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_facts( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionFacts("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionFacts( context.TODO(), "sessionId", &v2.MemoryGetSessionFactsRequest{}, ) ``` # Adds facts to a session ```http POST https://api.getzep.com/api/v2/sessions/{sessionId}/facts Content-Type: application/json ``` Deprecated API: Adds facts to a session ## Path Parameters - sessionId (required): Session ID ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/sessionId/facts \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "facts": [ { "fact": "fact" } ] }' ``` ```python from zep_cloud import NewFact from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session_facts( session_id="sessionId", facts=[ NewFact( fact="fact", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSessionFacts("sessionId", { facts: [{ fact: "fact" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSessionFacts( context.TODO(), "sessionId", &v2.AddFactsRequest{ Facts: []*v2.NewFact{ &v2.NewFact{ Fact: "fact", }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/facts \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "facts": [ { "fact": "string" } ] }' ``` ```python from zep_cloud import NewFact from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session_facts( session_id="sessionId", facts=[ NewFact( fact="fact", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSessionFacts("sessionId", { facts: [{ fact: "fact" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSessionFacts( context.TODO(), "sessionId", &v2.AddFactsRequest{ Facts: []*v2.NewFact{ &v2.NewFact{ Fact: "fact", }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/facts \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "facts": [ { "fact": "string" } ] }' ``` ```python from zep_cloud import NewFact from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add_session_facts( session_id="sessionId", facts=[ NewFact( fact="fact", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.addSessionFacts("sessionId", { facts: [{ fact: "fact" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.AddSessionFacts( context.TODO(), "sessionId", &v2.AddFactsRequest{ Facts: []*v2.NewFact{ &v2.NewFact{ Fact: "fact", }, }, }, ) ``` # Deprecated: Get Session Memory ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/memory ``` Deprecated: Returns a memory for a given session. Use thread.get_user_context instead. ## Path Parameters - sessionId (required): The ID of the session for which to retrieve memory. ## Query Parameters - lastn (optional): The number of most recent memory entries to retrieve. - minRating (optional): The minimum rating by which to filter relevant facts. ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/memory \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.get("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Get( context.TODO(), "sessionId", &v2.MemoryGetRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/memory \ -H "Authorization: Api-Key " \ -d lastn=0 \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.get("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Get( context.TODO(), "sessionId", &v2.MemoryGetRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/memory \ -H "Authorization: Api-Key " \ -d lastn=0 \ -d minRating=1 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.get("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Get( context.TODO(), "sessionId", &v2.MemoryGetRequest{}, ) ``` # Deprecated: Add Memory to Session ```http POST https://api.getzep.com/api/v2/sessions/{sessionId}/memory Content-Type: application/json ``` Deprecated: Add memory to the specified session. Use thread.add_messages instead. ## Path Parameters - sessionId (required): The ID of the session to which memory should be added. ## Response Body - 200: An object, optionally containing memory context retrieved for the last message - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/sessionId/memory \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "content": "content", "role_type": "norole" } ] }' ``` ```python from zep_cloud import Message from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add( session_id="sessionId", messages=[ Message( content="content", role_type="norole", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.add("sessionId", { messages: [{ content: "content", roleType: "norole" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Add( context.TODO(), "sessionId", &v2.AddMemoryRequest{ Messages: []*v2.Message{ &v2.Message{ Content: "content", RoleType: v2.RoleTypeNoRole, }, }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/sessions/:sessionId/memory \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{ "messages": [ { "content": "string", "role_type": "norole" } ] }' ``` ```python from zep_cloud import Message from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.add( session_id="sessionId", messages=[ Message( content="content", role_type="norole", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.add("sessionId", { messages: [{ content: "content", roleType: "norole" }] }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Add( context.TODO(), "sessionId", &v2.AddMemoryRequest{ Messages: []*v2.Message{ &v2.Message{ Content: "content", RoleType: v2.RoleTypeNoRole, }, }, }, ) ``` # Deprecated: Delete Session ```http DELETE https://api.getzep.com/api/v2/sessions/{sessionId}/memory ``` Deprecated: Deletes a session. Use thread.delete instead. ## Path Parameters - sessionId (required): The ID of the session for which memory should be deleted. ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/sessions/sessionId/memory \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.delete("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Delete( context.TODO(), "sessionId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/sessions/:sessionId/memory \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.delete("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Delete( context.TODO(), "sessionId", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/sessions/:sessionId/memory \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.delete( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.delete("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Delete( context.TODO(), "sessionId", ) ``` # Deprecated: Get Messages for Session ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/messages ``` Deprecated: Returns messages for a session. Use thread.get instead. ## Path Parameters - sessionId (required): Session ID ## Query Parameters - limit (optional): Limit the number of results returned - cursor (optional): Cursor for pagination ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/messages ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_messages( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessages("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessages( context.TODO(), "sessionId", &v2.MemoryGetSessionMessagesRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/messages \ -d limit=0 \ -d cursor=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_messages( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessages("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessages( context.TODO(), "sessionId", &v2.MemoryGetSessionMessagesRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/messages \ -d limit=0 \ -d cursor=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_messages( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessages("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessages( context.TODO(), "sessionId", &v2.MemoryGetSessionMessagesRequest{}, ) ``` # Get Message ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/messages/{messageUUID} ``` Deprecated: Use graph.episodes.get instead. Returns a specific message from a session. ## Path Parameters - sessionId (required): Soon to be deprecated as this is not needed. - messageUUID (required): The UUID of the message. ## Response Body - 200: The message. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/messages/messageUUID ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_message( session_id="sessionId", message_uuid="messageUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessage("sessionId", "messageUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessage( context.TODO(), "sessionId", "messageUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId/messages/:messageUUID ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_message( session_id="sessionId", message_uuid="messageUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessage("sessionId", "messageUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessage( context.TODO(), "sessionId", "messageUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId/messages/:messageUUID ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_session_message( session_id="sessionId", message_uuid="messageUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSessionMessage("sessionId", "messageUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSessionMessage( context.TODO(), "sessionId", "messageUUID", ) ``` # Updates the metadata of a message. ```http PATCH https://api.getzep.com/api/v2/sessions/{sessionId}/messages/{messageUUID} Content-Type: application/json ``` Updates the metadata of a message. ## Path Parameters - sessionId (required): The ID of the session. - messageUUID (required): The UUID of the message. ## Response Body - 200: The updated message. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/sessionId/messages/messageUUID \ -H "Content-Type: application/json" \ -d '{ "metadata": { "key": "value" } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_message_metadata( session_id="sessionId", message_uuid="messageUUID", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateMessageMetadata("sessionId", "messageUUID", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateMessageMetadata( context.TODO(), "sessionId", "messageUUID", &v2.ModelsMessageMetadataUpdate{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId/messages/:messageUUID \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_message_metadata( session_id="sessionId", message_uuid="messageUUID", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateMessageMetadata("sessionId", "messageUUID", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateMessageMetadata( context.TODO(), "sessionId", "messageUUID", &v2.ModelsMessageMetadataUpdate{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/sessions/:sessionId/messages/:messageUUID \ -H "Content-Type: application/json" \ -d '{ "metadata": { "string": {} } }' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.update_message_metadata( session_id="sessionId", message_uuid="messageUUID", metadata={"key": "value"}, ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.updateMessageMetadata("sessionId", "messageUUID", { metadata: { "key": "value" } }); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.UpdateMessageMetadata( context.TODO(), "sessionId", "messageUUID", &v2.ModelsMessageMetadataUpdate{ Metadata: map[string]interface{}{ "key": "value", }, }, ) ``` # Deprecated: Use search_sessions method instead ```http POST https://api.getzep.com/api/v2/sessions/{sessionId}/search Content-Type: application/json ``` ## Path Parameters - sessionId (required): The ID of the session for which memory should be searched. ## Query Parameters - limit (optional): The maximum number of search results to return. Defaults to None (no limit). ## Response Body - 200: A list of SearchResult objects representing the search results. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/sessions/sessionId/search \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.search( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.search("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Search( context.TODO(), "sessionId", &v2.MemorySearchPayload{}, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/sessions/:sessionId/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.search( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.search("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Search( context.TODO(), "sessionId", &v2.MemorySearchPayload{}, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/sessions/:sessionId/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.search( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.search("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.Search( context.TODO(), "sessionId", &v2.MemorySearchPayload{}, ) ``` # Returns a session's summaries by ID ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/summary ``` Deprecated API: Get session summaries by ID ## Path Parameters - sessionId (required): Session ID ## Response Body - 200: OK - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/summary \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_summaries( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSummaries("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSummaries( context.TODO(), "sessionId", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId/summary \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_summaries( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSummaries("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSummaries( context.TODO(), "sessionId", ) ``` ```shell curl https://api.getzep.com/api/v2/sessions/:sessionId/summary \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.get_summaries( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.getSummaries("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.GetSummaries( context.TODO(), "sessionId", ) ``` # Synthesize a question ```http GET https://api.getzep.com/api/v2/sessions/{sessionId}/synthesize_question ``` Deprecated API: Synthesize a question from the last N messages in the chat history. ## Path Parameters - sessionId (required): The ID of the session. ## Query Parameters - lastNMessages (optional): The number of messages to use for question synthesis. ## Response Body - 200: The synthesized question. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/sessions/sessionId/synthesize_question \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.synthesize_question( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.synthesizeQuestion("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.SynthesizeQuestion( context.TODO(), "sessionId", &v2.MemorySynthesizeQuestionRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/synthesize_question \ -H "Authorization: Api-Key " \ -d lastNMessages=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.synthesize_question( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.synthesizeQuestion("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.SynthesizeQuestion( context.TODO(), "sessionId", &v2.MemorySynthesizeQuestionRequest{}, ) ``` ```shell curl -G https://api.getzep.com/api/v2/sessions/:sessionId/synthesize_question \ -H "Authorization: Api-Key " \ -d lastNMessages=0 ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.memory.synthesize_question( session_id="sessionId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.memory.synthesizeQuestion("sessionId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Memory.SynthesizeQuestion( context.TODO(), "sessionId", &v2.MemorySynthesizeQuestionRequest{}, ) ``` # Get user facts. ```http GET https://api.getzep.com/api/v2/users/{userId}/facts ``` Deprecated: Use Get User Edges instead. ## Path Parameters - userId (required): The user_id of the user to get. ## Response Body - 200: The user facts. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/users/userId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_facts( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getFacts("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetFacts( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_facts( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getFacts("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetFacts( context.TODO(), "userId", ) ``` ```shell curl https://api.getzep.com/api/v2/users/:userId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.user.get_facts( user_id="userId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.user.getFacts("userId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.User.GetFacts( context.TODO(), "userId", ) ``` # Get Group Facts ```http GET https://api.getzep.com/api/v2/groups/{groupId}/facts ``` Deprecated: Use Get Group Edges instead. ## Path Parameters - groupId (required): The group_id of the group to get. ## Response Body - 200: The group facts. - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/groups/groupId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_facts( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getFacts("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetFacts( context.TODO(), "groupId", ) ``` ```shell curl https://api.getzep.com/api/v2/groups/:groupId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_facts( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getFacts("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetFacts( context.TODO(), "groupId", ) ``` ```shell curl https://api.getzep.com/api/v2/groups/:groupId/facts \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.group.get_facts( group_id="groupId", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.group.getFacts("groupId"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Group.GetFacts( context.TODO(), "groupId", ) ``` # Gets a list of DocumentCollections ```http GET https://api.getzep.com/api/v2/collections ``` Returns a list of all DocumentCollections. ## Response Body - 200: OK - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/collections \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.list_collections() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.listCollections(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.ListCollections( context.TODO(), ) ``` ```shell curl https://api.getzep.com/api/v2/collections \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.list_collections() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.listCollections(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.ListCollections( context.TODO(), ) ``` ```shell curl https://api.getzep.com/api/v2/collections \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.list_collections() ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.listCollections(); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.ListCollections( context.TODO(), ) ``` # Gets a DocumentCollection ```http GET https://api.getzep.com/api/v2/collections/{collectionName} ``` Returns a DocumentCollection if it exists. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/collections/collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.get_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetCollection( context.TODO(), "collectionName", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.get_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetCollection( context.TODO(), "collectionName", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.get_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetCollection( context.TODO(), "collectionName", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.get_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetCollection( context.TODO(), "collectionName", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.get_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetCollection( context.TODO(), "collectionName", ) ``` # Creates a new DocumentCollection ```http POST https://api.getzep.com/api/v2/collections/{collectionName} Content-Type: application/json ``` If a collection with the same name already exists, an error will be returned. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/collections/collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddCollection( context.TODO(), "collectionName", &v2.CreateDocumentCollectionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddCollection( context.TODO(), "collectionName", &v2.CreateDocumentCollectionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddCollection( context.TODO(), "collectionName", &v2.CreateDocumentCollectionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddCollection( context.TODO(), "collectionName", &v2.CreateDocumentCollectionRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddCollection( context.TODO(), "collectionName", &v2.CreateDocumentCollectionRequest{}, ) ``` # Deletes a DocumentCollection ```http DELETE https://api.getzep.com/api/v2/collections/{collectionName} ``` If a collection with the same name already exists, it will be overwritten. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteCollection( context.TODO(), "collectionName", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteCollection( context.TODO(), "collectionName", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteCollection( context.TODO(), "collectionName", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteCollection( context.TODO(), "collectionName", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteCollection( context.TODO(), "collectionName", ) ``` # Updates a DocumentCollection ```http PATCH https://api.getzep.com/api/v2/collections/{collectionName} Content-Type: application/json ``` Updates a DocumentCollection ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.update_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updateCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdateCollection( context.TODO(), "collectionName", &v2.UpdateDocumentCollectionRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.update_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updateCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdateCollection( context.TODO(), "collectionName", &v2.UpdateDocumentCollectionRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.update_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updateCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdateCollection( context.TODO(), "collectionName", &v2.UpdateDocumentCollectionRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.update_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updateCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdateCollection( context.TODO(), "collectionName", &v2.UpdateDocumentCollectionRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.update_collection( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updateCollection("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdateCollection( context.TODO(), "collectionName", &v2.UpdateDocumentCollectionRequest{}, ) ``` # Creates Multiple Documents in a DocumentCollection ```http POST https://api.getzep.com/api/v2/collections/{collectionName}/documents Content-Type: application/json ``` Creates Documents in a specified DocumentCollection and returns their UUIDs. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/collections/collectionName/documents \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "content": "content" } ]' ``` ```python from zep_cloud import CreateDocumentRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_documents( collection_name="collectionName", request=[ CreateDocumentRequest( content="content", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addDocuments("collectionName", [{ content: "content" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddDocuments( context.TODO(), "collectionName", []*v2.CreateDocumentRequest{ &v2.CreateDocumentRequest{ Content: "content", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "content": "string" } ]' ``` ```python from zep_cloud import CreateDocumentRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_documents( collection_name="collectionName", request=[ CreateDocumentRequest( content="content", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addDocuments("collectionName", [{ content: "content" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddDocuments( context.TODO(), "collectionName", []*v2.CreateDocumentRequest{ &v2.CreateDocumentRequest{ Content: "content", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "content": "string" } ]' ``` ```python from zep_cloud import CreateDocumentRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_documents( collection_name="collectionName", request=[ CreateDocumentRequest( content="content", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addDocuments("collectionName", [{ content: "content" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddDocuments( context.TODO(), "collectionName", []*v2.CreateDocumentRequest{ &v2.CreateDocumentRequest{ Content: "content", }, }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "content": "string" } ]' ``` ```python from zep_cloud import CreateDocumentRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.add_documents( collection_name="collectionName", request=[ CreateDocumentRequest( content="content", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.addDocuments("collectionName", [{ content: "content" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.AddDocuments( context.TODO(), "collectionName", []*v2.CreateDocumentRequest{ &v2.CreateDocumentRequest{ Content: "content", }, }, ) ``` # Batch Deletes Documents from a DocumentCollection by UUID ```http POST https://api.getzep.com/api/v2/collections/{collectionName}/documents/batchDelete Content-Type: application/json ``` Deletes specified Documents from a DocumentCollection. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/collections/collectionName/documents/batchDelete \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ "string" ]' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_delete_documents( collection_name="collectionName", request=["string"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchDeleteDocuments("collectionName", ["string"]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchDeleteDocuments( context.TODO(), "collectionName", []string{ "string", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchDelete \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ "string" ]' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_delete_documents( collection_name="collectionName", request=["string"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchDeleteDocuments("collectionName", ["string"]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchDeleteDocuments( context.TODO(), "collectionName", []string{ "string", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchDelete \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ "string" ]' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_delete_documents( collection_name="collectionName", request=["string"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchDeleteDocuments("collectionName", ["string"]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchDeleteDocuments( context.TODO(), "collectionName", []string{ "string", }, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchDelete \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ "string" ]' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_delete_documents( collection_name="collectionName", request=["string"], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchDeleteDocuments("collectionName", ["string"]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchDeleteDocuments( context.TODO(), "collectionName", []string{ "string", }, ) ``` # Batch Gets Documents from a DocumentCollection ```http POST https://api.getzep.com/api/v2/collections/{collectionName}/documents/batchGet Content-Type: application/json ``` Returns Documents from a DocumentCollection specified by UUID or ID. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/collections/collectionName/documents/batchGet \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_get_documents( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchGetDocuments("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchGetDocuments( context.TODO(), "collectionName", &v2.GetDocumentListRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchGet \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_get_documents( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchGetDocuments("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchGetDocuments( context.TODO(), "collectionName", &v2.GetDocumentListRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchGet \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_get_documents( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchGetDocuments("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchGetDocuments( context.TODO(), "collectionName", &v2.GetDocumentListRequest{}, ) ``` ```shell curl -X POST https://api.getzep.com/api/v2/collections/:collectionName/documents/batchGet \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_get_documents( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchGetDocuments("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchGetDocuments( context.TODO(), "collectionName", &v2.GetDocumentListRequest{}, ) ``` # Batch Updates Documents in a DocumentCollection ```http PATCH https://api.getzep.com/api/v2/collections/{collectionName}/documents/batchUpdate Content-Type: application/json ``` Updates Documents in a specified DocumentCollection. ## Path Parameters - collectionName (required): Name of the Document Collection ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/collectionName/documents/batchUpdate \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "uuid": "uuid" } ]' ``` ```python from zep_cloud import UpdateDocumentListRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_update_documents( collection_name="collectionName", request=[ UpdateDocumentListRequest( uuid_="uuid", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchUpdateDocuments("collectionName", [{ uuid: "uuid" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchUpdateDocuments( context.TODO(), "collectionName", []*v2.UpdateDocumentListRequest{ &v2.UpdateDocumentListRequest{ UUID: "uuid", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/batchUpdate \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "uuid": "string" } ]' ``` ```python from zep_cloud import UpdateDocumentListRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_update_documents( collection_name="collectionName", request=[ UpdateDocumentListRequest( uuid_="uuid", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchUpdateDocuments("collectionName", [{ uuid: "uuid" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchUpdateDocuments( context.TODO(), "collectionName", []*v2.UpdateDocumentListRequest{ &v2.UpdateDocumentListRequest{ UUID: "uuid", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/batchUpdate \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "uuid": "string" } ]' ``` ```python from zep_cloud import UpdateDocumentListRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_update_documents( collection_name="collectionName", request=[ UpdateDocumentListRequest( uuid_="uuid", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchUpdateDocuments("collectionName", [{ uuid: "uuid" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchUpdateDocuments( context.TODO(), "collectionName", []*v2.UpdateDocumentListRequest{ &v2.UpdateDocumentListRequest{ UUID: "uuid", }, }, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/batchUpdate \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '[ { "uuid": "string" } ]' ``` ```python from zep_cloud import UpdateDocumentListRequest from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.batch_update_documents( collection_name="collectionName", request=[ UpdateDocumentListRequest( uuid_="uuid", ) ], ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.batchUpdateDocuments("collectionName", [{ uuid: "uuid" }]); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.BatchUpdateDocuments( context.TODO(), "collectionName", []*v2.UpdateDocumentListRequest{ &v2.UpdateDocumentListRequest{ UUID: "uuid", }, }, ) ``` # Gets a Document from a DocumentCollection by UUID ```http GET https://api.getzep.com/api/v2/collections/{collectionName}/documents/uuid/{documentUUID} ``` Returns specified Document from a DocumentCollection. ## Path Parameters - collectionName (required): Name of the Document Collection - documentUUID (required): UUID of the Document to be updated ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl https://api.getzep.com/api/v2/collections/collectionName/documents/uuid/documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.gets_a_document_from_a_document_collection_by_uuid( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getsADocumentFromADocumentCollectionByUuid("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetsADocumentFromADocumentCollectionByUUID( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.gets_a_document_from_a_document_collection_by_uuid( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getsADocumentFromADocumentCollectionByUuid("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetsADocumentFromADocumentCollectionByUUID( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.gets_a_document_from_a_document_collection_by_uuid( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getsADocumentFromADocumentCollectionByUuid("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetsADocumentFromADocumentCollectionByUUID( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.gets_a_document_from_a_document_collection_by_uuid( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.getsADocumentFromADocumentCollectionByUuid("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.GetsADocumentFromADocumentCollectionByUUID( context.TODO(), "collectionName", "documentUUID", ) ``` # Delete Document from a DocumentCollection by UUID ```http DELETE https://api.getzep.com/api/v2/collections/{collectionName}/documents/uuid/{documentUUID} ``` Delete specified Document from a DocumentCollection. ## Path Parameters - collectionName (required): Name of the Document Collection - documentUUID (required): UUID of the Document to be deleted ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Document Not Found - 500: Internal Server Error ## Examples ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/collectionName/documents/uuid/documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteDocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteDocument( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteDocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteDocument( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteDocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteDocument( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteDocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteDocument( context.TODO(), "collectionName", "documentUUID", ) ``` ```shell curl -X DELETE https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.delete_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.deleteDocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.DeleteDocument( context.TODO(), "collectionName", "documentUUID", ) ``` # Updates a Document ```http PATCH https://api.getzep.com/api/v2/collections/{collectionName}/documents/uuid/{documentUUID} Content-Type: application/json ``` Updates a Document in a DocumentCollection by UUID ## Path Parameters - collectionName (required): Name of the Document Collection - documentUUID (required): UUID of the Document to be updated ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 404: Not Found - 500: Internal Server Error ## Examples ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/collectionName/documents/uuid/documentUUID \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.updates_a_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updatesADocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdatesADocument( context.TODO(), "collectionName", "documentUUID", &v2.UpdateDocumentRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.updates_a_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updatesADocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdatesADocument( context.TODO(), "collectionName", "documentUUID", &v2.UpdateDocumentRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.updates_a_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updatesADocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdatesADocument( context.TODO(), "collectionName", "documentUUID", &v2.UpdateDocumentRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.updates_a_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updatesADocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdatesADocument( context.TODO(), "collectionName", "documentUUID", &v2.UpdateDocumentRequest{}, ) ``` ```shell curl -X PATCH https://api.getzep.com/api/v2/collections/:collectionName/documents/uuid/:documentUUID \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.updates_a_document( collection_name="collectionName", document_uuid="documentUUID", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.updatesADocument("collectionName", "documentUUID"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.UpdatesADocument( context.TODO(), "collectionName", "documentUUID", &v2.UpdateDocumentRequest{}, ) ``` # Searches Documents in a DocumentCollection ```http POST https://api.getzep.com/api/v2/collections/{collectionName}/search Content-Type: application/json ``` Searches over documents in a collection based on provided search criteria. One of text or metadata must be provided. Returns an empty list if no documents are found. ## Path Parameters - collectionName (required): Name of the Document Collection ## Query Parameters - limit (optional): Limit the number of returned documents ## Response Body - 200: OK - 400: Bad Request - 401: Unauthorized - 500: Internal Server Error ## Examples ```shell curl -X POST https://api.getzep.com/api/v2/collections/collectionName/search \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.search( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.search("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.Search( context.TODO(), "collectionName", &v2.DocumentSearchPayload{}, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/collections/:collectionName/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.search( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.search("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.Search( context.TODO(), "collectionName", &v2.DocumentSearchPayload{}, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/collections/:collectionName/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.search( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.search("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.Search( context.TODO(), "collectionName", &v2.DocumentSearchPayload{}, ) ``` ```shell curl -X POST "https://api.getzep.com/api/v2/collections/:collectionName/search?limit=0" \ -H "Authorization: Api-Key " \ -H "Content-Type: application/json" \ -d '{}' ``` ```python from zep_cloud.client import Zep client = Zep( api_key="YOUR_API_KEY", ) client.document.search( collection_name="collectionName", ) ``` ```typescript import { ZepClient } from "zep-cloud"; const client = new ZepClient({ apiKey: "YOUR_API_KEY" }); await client.document.search("collectionName"); ``` ```go import ( context "context" option "github.com/getzep/zep-go/v2/option" v2 "github.com/getzep/zep-go/v2" v2client "github.com/getzep/zep-go/v2/client" ) client := v2client.NewClient( option.WithAPIKey( "", ), ) response, err := client.Document.Search( context.TODO(), "collectionName", &v2.DocumentSearchPayload{}, ) ``` # Welcome to Graphiti! Want to use Graphiti with AI assistants like Claude Desktop or Cursor? Check out the [Knowledge Graph MCP Server](mcp-server). Graphiti is a Python framework for building temporally-aware knowledge graphs designed for AI agents. It enables real-time incremental updates to knowledge graphs without batch recomputation, making it suitable for dynamic environments where relationships and information evolve over time. Learn about Graphiti's core concepts and how temporal knowledge graphs work. Get up and running with Graphiti in minutes including installation, episodes, search, and basic operations. Use Graphiti with AI assistants like Claude Desktop or Cursor. Learn how to add text and JSON episodes to build your knowledge graph. Discover hybrid search capabilities combining semantic, keyword, and graph-based retrieval. Define domain-specific entity types for more precise knowledge representation. # Overview > Temporal Knowledge Graphs for Agentic Applications Graphiti helps you create and query Knowledge Graphs that evolve over time. A knowledge graph is a network of interconnected facts, such as *“Kendra loves Adidas shoes.”* Each fact is a *“triplet”* represented by two entities, or nodes (*”Kendra”, “Adidas shoes”*), and their relationship, or edge (*”loves”*).
Knowledge Graphs have been explored extensively for information retrieval. What makes Graphiti unique is its ability to autonomously build a knowledge graph while handling changing relationships and maintaining historical context.
![graphiti intro slides](file:34e08b39-3f7d-4aab-b4f8-9389d1300d4e) Graphiti builds dynamic, temporally-aware knowledge graphs that represent complex, evolving relationships between entities over time. It ingests both unstructured and structured data, and the resulting graph may be queried using a fusion of time, full-text, semantic, and graph algorithm approaches. With Graphiti, you can build LLM applications such as: * Assistants that learn from user interactions, fusing personal knowledge with dynamic data from business systems like CRMs and billing platforms. * Agents that autonomously execute complex tasks, reasoning with state changes from multiple dynamic sources. Graphiti supports a wide range of applications in sales, customer service, health, finance, and more, enabling long-term recall and state-based reasoning for both assistants and agents. ## Graphiti and Zep Memory Graphiti powers the core of [Zep's memory layer](https://www.getzep.com) for LLM-powered Assistants and Agents. We're excited to open-source Graphiti, believing its potential reaches far beyond memory applications. ## Why Graphiti? We were intrigued by Microsoft’s GraphRAG, which expanded on RAG text chunking by using a graph to better model a document corpus and making this representation available via semantic and graph search techniques. However, GraphRAG did not address our core problem: It's primarily designed for static documents and doesn't inherently handle temporal aspects of data. Graphiti is designed from the ground up to handle constantly changing information, hybrid semantic and graph search, and scale: * **Temporal Awareness:** Tracks changes in facts and relationships over time, enabling point-in-time queries. Graph edges include temporal metadata to record relationship lifecycles. * **Episodic Processing:** Ingests data as discrete episodes, maintaining data provenance and allowing incremental entity and relationship extraction. * **Custom Entity Types:** Supports defining domain-specific entity types, enabling more precise knowledge representation for specialized applications. * **Hybrid Search:** Combines semantic and BM25 full-text search, with the ability to rerank results by distance from a central node e.g. "Kendra". * **Scalable:** Designed for processing large datasets, with parallelization of LLM calls for bulk processing while preserving the chronology of events. * **Supports Varied Sources:** Can ingest both unstructured text and structured JSON data. | Aspect | GraphRAG | Graphiti | | -------------------------- | ------------------------------------- | ------------------------------------------------ | | **Primary Use** | Static document summarization | Dynamic data management | | **Data Handling** | Batch-oriented processing | Continuous, incremental updates | | **Knowledge Structure** | Entity clusters & community summaries | Episodic data, semantic entities, communities | | **Retrieval Method** | Sequential LLM summarization | Hybrid semantic, keyword, and graph-based search | | **Adaptability** | Low | High | | **Temporal Handling** | Basic timestamp tracking | Explicit bi-temporal tracking | | **Contradiction Handling** | LLM-driven summarization judgments | Temporal edge invalidation | | **Query Latency** | Seconds to tens of seconds | Typically sub-second latency | | **Custom Entity Types** | No | Yes, customizable | | **Scalability** | Moderate | High, optimized for large datasets | Graphiti is specifically designed to address the challenges of dynamic and frequently updated datasets, making it particularly suitable for applications requiring real-time interaction and precise historical queries. ![graphiti demo slides](file:5345df00-e1af-4536-8558-fadef72fd18b) # Quick Start > Getting started with Graphiti For complete working examples, check out the [Graphiti Quickstart Examples](https://github.com/getzep/graphiti/tree/main/examples/quickstart) on GitHub. ## Installation Requirements: * Python 3.10 or higher * Neo4j 5.26 or higher or FalkorDB 1.1.2 or higher (see [Graph Database Configuration](graph-database-configuration) for setup options) * OpenAI API key (Graphiti defaults to OpenAI for LLM inference and embedding) The simplest way to install Neo4j is via [Neo4j Desktop](https://neo4j.com/download/). It provides a user-friendly interface to manage Neo4j instances and databases. ```bash pip install graphiti-core ``` or ```bash uv add graphiti-core ``` ### Alternative LLM Providers While Graphiti defaults to OpenAI, it supports multiple LLM providers including Azure OpenAI, Google Gemini, Anthropic, Groq, and local models via Ollama. For detailed configuration instructions, see our [LLM Configuration](llm-configuration) guide. ### Environment Variables Set your OpenAI API key: ```bash export OPENAI_API_KEY=your_openai_api_key_here ``` #### Optional Variables * `USE_PARALLEL_RUNTIME`: Enable Neo4j's parallel runtime feature for search queries (not supported in Community Edition) * `GRAPHITI_TELEMETRY_ENABLED`: Set to `false` to disable anonymous telemetry collection ## Getting Started with Graphiti For a comprehensive overview of Graphiti and its capabilities, check out the [Overview](overview) page. ### Required Imports First, import the necessary libraries for working with Graphiti: ```python import asyncio import json import logging import os from datetime import datetime, timezone from logging import INFO from dotenv import load_dotenv from graphiti_core import Graphiti from graphiti_core.nodes import EpisodeType from graphiti_core.search.search_config_recipes import NODE_HYBRID_SEARCH_RRF ``` ### Configuration Graphiti uses OpenAI by default for LLM inference and embedding. Ensure that an `OPENAI_API_KEY` is set in your environment. Support for multiple LLM providers is available - see our [LLM Configuration](llm-configuration) guide. Graphiti also requires Neo4j connection parameters. Set the following environment variables: * `NEO4J_URI`: The URI of your Neo4j database (default: bolt://localhost:7687) * `NEO4J_USER`: Your Neo4j username (default: neo4j) * `NEO4J_PASSWORD`: Your Neo4j password For detailed database setup instructions, see our [Graph Database Configuration](graph-database-configuration) guide. Set up logging and environment variables for connecting to the Neo4j database: ```python # Configure logging logging.basicConfig( level=INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', datefmt='%Y-%m-%d %H:%M:%S', ) logger = logging.getLogger(__name__) load_dotenv() # Neo4j connection parameters # Make sure Neo4j Desktop is running with a local DBMS started neo4j_uri = os.environ.get('NEO4J_URI', 'bolt://localhost:7687') neo4j_user = os.environ.get('NEO4J_USER', 'neo4j') neo4j_password = os.environ.get('NEO4J_PASSWORD', 'password') if not neo4j_uri or not neo4j_user or not neo4j_password: raise ValueError('NEO4J_URI, NEO4J_USER, and NEO4J_PASSWORD must be set') ``` ### Main Function Create an async main function to run all Graphiti operations: ```python async def main(): # Main function implementation will go here pass if __name__ == '__main__': asyncio.run(main()) ``` ### Initialization Connect to Neo4j and set up Graphiti indices. This is required before using other Graphiti functionality: ```python # Initialize Graphiti with Neo4j connection graphiti = Graphiti(neo4j_uri, neo4j_user, neo4j_password) try: # Initialize the graph database with graphiti's indices. This only needs to be done once. await graphiti.build_indices_and_constraints() # Additional code will go here finally: # Close the connection await graphiti.close() print('\nConnection closed') ``` ### Adding Episodes Episodes are the primary units of information in Graphiti. They can be text or structured JSON and are automatically processed to extract entities and relationships. For more detailed information on episodes and bulk loading, see the [Adding Episodes](adding-episodes) page: ```python # Episodes list containing both text and JSON episodes episodes = [ { 'content': 'Kamala Harris is the Attorney General of California. She was previously ' 'the district attorney for San Francisco.', 'type': EpisodeType.text, 'description': 'podcast transcript', }, { 'content': 'As AG, Harris was in office from January 3, 2011 – January 3, 2017', 'type': EpisodeType.text, 'description': 'podcast transcript', }, { 'content': { 'name': 'Gavin Newsom', 'position': 'Governor', 'state': 'California', 'previous_role': 'Lieutenant Governor', 'previous_location': 'San Francisco', }, 'type': EpisodeType.json, 'description': 'podcast metadata', }, { 'content': { 'name': 'Gavin Newsom', 'position': 'Governor', 'term_start': 'January 7, 2019', 'term_end': 'Present', }, 'type': EpisodeType.json, 'description': 'podcast metadata', }, ] # Add episodes to the graph for i, episode in enumerate(episodes): await graphiti.add_episode( name=f'Freakonomics Radio {i}', episode_body=episode['content'] if isinstance(episode['content'], str) else json.dumps(episode['content']), source=episode['type'], source_description=episode['description'], reference_time=datetime.now(timezone.utc), ) print(f'Added episode: Freakonomics Radio {i} ({episode["type"].value})') ``` ### Basic Search The simplest way to retrieve relationships (edges) from Graphiti is using the search method, which performs a hybrid search combining semantic similarity and BM25 text retrieval. For more details on search capabilities, see the [Searching the Graph](searching) page: ```python # Perform a hybrid search combining semantic similarity and BM25 retrieval print("\nSearching for: 'Who was the California Attorney General?'") results = await graphiti.search('Who was the California Attorney General?') # Print search results print('\nSearch Results:') for result in results: print(f'UUID: {result.uuid}') print(f'Fact: {result.fact}') if hasattr(result, 'valid_at') and result.valid_at: print(f'Valid from: {result.valid_at}') if hasattr(result, 'invalid_at') and result.invalid_at: print(f'Valid until: {result.invalid_at}') print('---') ``` ### Center Node Search For more contextually relevant results, you can use a center node to rerank search results based on their graph distance to a specific node. This is particularly useful for entity-specific queries as described in the [Searching the Graph](searching) page: ```python # Use the top search result's UUID as the center node for reranking if results and len(results) > 0: # Get the source node UUID from the top result center_node_uuid = results[0].source_node_uuid print('\nReranking search results based on graph distance:') print(f'Using center node UUID: {center_node_uuid}') reranked_results = await graphiti.search( 'Who was the California Attorney General?', center_node_uuid=center_node_uuid ) # Print reranked search results print('\nReranked Search Results:') for result in reranked_results: print(f'UUID: {result.uuid}') print(f'Fact: {result.fact}') if hasattr(result, 'valid_at') and result.valid_at: print(f'Valid from: {result.valid_at}') if hasattr(result, 'invalid_at') and result.invalid_at: print(f'Valid until: {result.invalid_at}') print('---') else: print('No results found in the initial search to use as center node.') ``` ### Node Search Using Search Recipes Graphiti provides predefined search recipes optimized for different search scenarios. Here we use NODE\_HYBRID\_SEARCH\_RRF for retrieving nodes directly instead of edges. For a complete list of available search recipes and reranking approaches, see the [Configurable Search Strategies](searching#configurable-search-strategies) section in the Searching documentation: ```python # Example: Perform a node search using _search method with standard recipes print( '\nPerforming node search using _search method with standard recipe NODE_HYBRID_SEARCH_RRF:' ) # Use a predefined search configuration recipe and modify its limit node_search_config = NODE_HYBRID_SEARCH_RRF.model_copy(deep=True) node_search_config.limit = 5 # Limit to 5 results # Execute the node search node_search_results = await graphiti._search( query='California Governor', config=node_search_config, ) # Print node search results print('\nNode Search Results:') for node in node_search_results.nodes: print(f'Node UUID: {node.uuid}') print(f'Node Name: {node.name}') node_summary = node.summary[:100] + '...' if len(node.summary) > 100 else node.summary print(f'Content Summary: {node_summary}') print(f"Node Labels: {', '.join(node.labels)}") print(f'Created At: {node.created_at}') if hasattr(node, 'attributes') and node.attributes: print('Attributes:') for key, value in node.attributes.items(): print(f' {key}: {value}') print('---') ``` ### Complete Example For a complete working example that puts all these concepts together, check out the [Graphiti Quickstart Examples](https://github.com/getzep/graphiti/tree/main/examples/quickstart) on GitHub. ## Next Steps Now that you've learned the basics of Graphiti, you can explore more advanced features: * [Custom Entity Types](custom-entity-types): Learn how to define and use custom entity types to better model your domain-specific knowledge * [Communities](communities): Discover how to work with communities, which are groups of related nodes that share common attributes or relationships * [Advanced Search Techniques](searching): Explore more sophisticated search strategies, including different reranking approaches and configurable search recipes * [Adding Fact Triples](adding-fact-triples): Learn how to directly add fact triples to your graph for more precise knowledge representation * [Agent Integration](agent): Discover how to integrate Graphiti with LLM agents for more powerful AI applications Make sure to run await statements within an [async function](https://docs.python.org/3/library/asyncio-task.html). # Knowledge Graph MCP Server > A Knowledge Graph MCP Server for AI Assistants The Graphiti MCP Server is an experimental implementation that exposes Graphiti's key functionality through the Model Context Protocol (MCP). This enables AI assistants like Claude Desktop and Cursor to interact with Graphiti's knowledge graph capabilities, providing persistent memory and contextual awareness. The Graphiti MCP Server bridges AI assistants with Graphiti's temporally-aware knowledge graphs, allowing assistants to maintain persistent memory across conversations and sessions. By integrating through MCP, assistants can automatically store, retrieve, and reason with information from their interactions. ## Key Features The MCP server exposes Graphiti's core capabilities: * **Episode Management**: Add, retrieve, and delete episodes (text, messages, or JSON data) * **Entity Management**: Search and manage entity nodes and relationships * **Search Capabilities**: Semantic and hybrid search for facts and node summaries * **Group Management**: Organize data with group\_id filtering for multi-user scenarios * **Graph Maintenance**: Clear graphs and rebuild indices as needed ## Quick Start with OpenAI This quick start assumes you have OpenAI API access. For other LLM providers and detailed configuration options, see the [MCP Server README](https://github.com/getzep/graphiti/blob/main/mcp_server/README.md). ### Prerequisites Before getting started, ensure you have: 1. **Python 3.10+** installed on your system 2. **Neo4j database** (version 5.26 or later) running locally or accessible remotely 3. **OpenAI API key** for LLM operations and embeddings ### Installation 1. Clone the Graphiti repository: ```bash git clone https://github.com/getzep/graphiti.git cd graphiti ``` 2. Navigate to the MCP server directory and install dependencies: ```bash cd mcp_server uv sync ``` ### Configuration Set up your environment variables in a `.env` file: ```bash # Required OPENAI_API_KEY=your_openai_api_key_here MODEL_NAME=gpt-4o-mini # Neo4j Configuration (adjust as needed) NEO4J_URI=bolt://localhost:7687 NEO4J_USER=neo4j NEO4J_PASSWORD=your_neo4j_password ``` ### Running the Server Start the MCP server: ```bash uv run graphiti_mcp_server.py ``` For development with custom options: ```bash uv run graphiti_mcp_server.py --model gpt-4o-mini --transport sse --group-id my-project ``` ## MCP Client Integration ### Claude Desktop Configure Claude Desktop to connect via the stdio transport: ```json { "mcpServers": { "graphiti-memory": { "transport": "stdio", "command": "/path/to/uv", "args": [ "run", "--directory", "/path/to/graphiti/mcp_server", "graphiti_mcp_server.py", "--transport", "stdio" ], "env": { "OPENAI_API_KEY": "your_api_key", "MODEL_NAME": "gpt-4o-mini", "NEO4J_URI": "bolt://localhost:7687", "NEO4J_USER": "neo4j", "NEO4J_PASSWORD": "your_password" } } } } ``` ### Cursor IDE For Cursor, use the SSE transport configuration: ```json { "mcpServers": { "graphiti-memory": { "url": "http://localhost:8000/sse" } } } ``` ## Available Tools Once connected, AI assistants have access to these Graphiti tools: * `add_memory` - Store episodes and interactions in the knowledge graph * `search_facts` - Find relevant facts and relationships * `search_nodes` - Search for entity summaries and information * `get_episodes` - Retrieve recent episodes for context * `delete_episode` - Remove episodes from the graph * `clear_graph` - Reset the knowledge graph entirely ## Docker Deployment For containerized deployment, use the provided Docker Compose setup: ```bash docker compose up ``` This starts both Neo4j and the MCP server with SSE transport enabled. ## Next Steps For comprehensive configuration options, advanced features, and troubleshooting: * **Full Documentation**: See the complete [MCP Server README](https://github.com/getzep/graphiti/blob/main/mcp_server/README.md) * **Integration Examples**: Explore client-specific setup guides for Claude Desktop and Cursor * **Custom Entity Types**: Configure domain-specific entity extraction * **Multi-tenant Setup**: Use group IDs for organizing data across different contexts The MCP server is experimental and under active development. Features and APIs may change between releases. # LLM Configuration > Configure Graphiti with different LLM providers Graphiti works best with LLM services that support Structured Output (such as OpenAI and Gemini). Using other services may result in incorrect output schemas and ingestion failures, particularly when using smaller models. Graphiti defaults to using OpenAI for LLM inference and embeddings, but supports multiple LLM providers including Azure OpenAI, Google Gemini, Anthropic, Groq, and local models via Ollama. This guide covers configuring Graphiti with alternative LLM providers. ## Azure OpenAI Azure OpenAI deployments often require different endpoints for LLM and embedding services, and separate deployments for default and small models. ### Installation ```bash pip install graphiti-core ``` ### Configuration ```python from openai import AsyncAzureOpenAI from graphiti_core import Graphiti from graphiti_core.llm_client import LLMConfig, OpenAIClient from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient # Azure OpenAI configuration - use separate endpoints for different services api_key = "" api_version = "" llm_endpoint = "" # e.g., "https://your-llm-resource.openai.azure.com/" embedding_endpoint = "" # e.g., "https://your-embedding-resource.openai.azure.com/" # Create separate Azure OpenAI clients for different services llm_client_azure = AsyncAzureOpenAI( api_key=api_key, api_version=api_version, azure_endpoint=llm_endpoint ) embedding_client_azure = AsyncAzureOpenAI( api_key=api_key, api_version=api_version, azure_endpoint=embedding_endpoint ) # Create LLM Config with your Azure deployment names azure_llm_config = LLMConfig( small_model="gpt-4.1-nano", model="gpt-4.1-mini", ) # Initialize Graphiti with Azure OpenAI clients graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=OpenAIClient( llm_config=azure_llm_config, client=llm_client_azure ), embedder=OpenAIEmbedder( config=OpenAIEmbedderConfig( embedding_model="text-embedding-3-small-deployment" # Your Azure embedding deployment name ), client=embedding_client_azure ), cross_encoder=OpenAIRerankerClient( llm_config=LLMConfig( model=azure_llm_config.small_model # Use small model for reranking ), client=llm_client_azure ) ) ``` Make sure to replace the placeholder values with your actual Azure OpenAI credentials and deployment names. ### Environment Variables Azure OpenAI can also be configured using environment variables: * `AZURE_OPENAI_ENDPOINT` - Azure OpenAI LLM endpoint URL * `AZURE_OPENAI_DEPLOYMENT_NAME` - Azure OpenAI LLM deployment name * `AZURE_OPENAI_API_VERSION` - Azure OpenAI API version * `AZURE_OPENAI_EMBEDDING_API_KEY` - Azure OpenAI Embedding deployment key (if different from `OPENAI_API_KEY`) * `AZURE_OPENAI_EMBEDDING_ENDPOINT` - Azure OpenAI Embedding endpoint URL * `AZURE_OPENAI_EMBEDDING_DEPLOYMENT_NAME` - Azure OpenAI embedding deployment name * `AZURE_OPENAI_EMBEDDING_API_VERSION` - Azure OpenAI embedding API version * `AZURE_OPENAI_USE_MANAGED_IDENTITY` - Use Azure Managed Identities for authentication ## Google Gemini Google's Gemini models provide excellent structured output support and can be used for LLM inference, embeddings, and cross-encoding/reranking. ### Installation ```bash pip install "graphiti-core[google-genai]" ``` ### Configuration ```python from graphiti_core import Graphiti from graphiti_core.llm_client.gemini_client import GeminiClient, LLMConfig from graphiti_core.embedder.gemini import GeminiEmbedder, GeminiEmbedderConfig from graphiti_core.cross_encoder.gemini_reranker_client import GeminiRerankerClient # Google API key configuration api_key = "" # Initialize Graphiti with Gemini clients graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=GeminiClient( config=LLMConfig( api_key=api_key, model="gemini-2.0-flash" ) ), embedder=GeminiEmbedder( config=GeminiEmbedderConfig( api_key=api_key, embedding_model="embedding-001" ) ), cross_encoder=GeminiRerankerClient( config=LLMConfig( api_key=api_key, model="gemini-2.0-flash-exp" ) ) ) ``` The Gemini reranker uses the `gemini-2.0-flash-exp` model by default, which is optimized for cost-effective and low-latency classification tasks. ### Environment Variables Google Gemini can be configured using: * `GOOGLE_API_KEY` - Your Google API key ## Anthropic Anthropic's Claude models can be used for LLM inference with OpenAI embeddings and reranking. When using Anthropic for LLM inference, you still need an OpenAI API key for embeddings and reranking functionality. Make sure to set both `ANTHROPIC_API_KEY` and `OPENAI_API_KEY` environment variables. ### Installation ```bash pip install "graphiti-core[anthropic]" ``` ### Configuration ```python from graphiti_core import Graphiti from graphiti_core.llm_client.anthropic_client import AnthropicClient, LLMConfig from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient # Configure Anthropic LLM with OpenAI embeddings and reranking graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=AnthropicClient( config=LLMConfig( api_key="", model="claude-sonnet-4-20250514", small_model="claude-3-5-haiku-20241022" ) ), embedder=OpenAIEmbedder( config=OpenAIEmbedderConfig( api_key="", embedding_model="text-embedding-3-small" ) ), cross_encoder=OpenAIRerankerClient( config=LLMConfig( api_key="", model="gpt-4.1-nano" # Use a smaller model for reranking ) ) ) ``` ### Environment Variables Anthropic can be configured using: * `ANTHROPIC_API_KEY` - Your Anthropic API key * `OPENAI_API_KEY` - Required for embeddings and reranking ## Groq Groq provides fast inference with various open-source models, using OpenAI for embeddings and reranking. When using Groq, avoid smaller models as they may not accurately extract data or output the correct JSON structures required by Graphiti. Use larger, more capable models like Llama 3.1 70B for best results. ### Installation ```bash pip install "graphiti-core[groq]" ``` ### Configuration ```python from graphiti_core import Graphiti from graphiti_core.llm_client.groq_client import GroqClient, LLMConfig from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient # Configure Groq LLM with OpenAI embeddings and reranking graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=GroqClient( config=LLMConfig( api_key="", model="llama-3.1-70b-versatile", small_model="llama-3.1-8b-instant" ) ), embedder=OpenAIEmbedder( config=OpenAIEmbedderConfig( api_key="", embedding_model="text-embedding-3-small" ) ), cross_encoder=OpenAIRerankerClient( config=LLMConfig( api_key="", model="gpt-4.1-nano" # Use a smaller model for reranking ) ) ) ``` ### Environment Variables Groq can be configured using: * `GROQ_API_KEY` - Your Groq API key * `OPENAI_API_KEY` - Required for embeddings ## Ollama (Local LLMs) Ollama enables running local LLMs and embedding models via its OpenAI-compatible API, ideal for privacy-focused applications or avoiding API costs. When using Ollama, avoid smaller local models as they may not accurately extract data or output the correct JSON structures required by Graphiti. Use larger, more capable models and ensure they support structured output for reliable knowledge graph construction. ### Installation First, install and configure Ollama: ```bash # Install Ollama (visit https://ollama.ai for installation instructions) # Then pull the models you want to use: ollama pull deepseek-r1:7b # LLM ollama pull nomic-embed-text # embeddings ``` ### Configuration ```python from graphiti_core import Graphiti from graphiti_core.llm_client.config import LLMConfig from graphiti_core.llm_client.openai_client import OpenAIClient from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient # Configure Ollama LLM client llm_config = LLMConfig( api_key="abc", # Ollama doesn't require a real API key model="deepseek-r1:7b", small_model="deepseek-r1:7b", base_url="http://localhost:11434/v1", # Ollama provides this port ) llm_client = OpenAIClient(config=llm_config) # Initialize Graphiti with Ollama clients graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=llm_client, embedder=OpenAIEmbedder( config=OpenAIEmbedderConfig( api_key="abc", embedding_model="nomic-embed-text", embedding_dim=768, base_url="http://localhost:11434/v1", ) ), cross_encoder=OpenAIRerankerClient(client=llm_client, config=llm_config), ) ``` Ensure Ollama is running (`ollama serve`) and that you have pulled the models you want to use. ## OpenAI Compatible Services Many LLM providers offer OpenAI-compatible APIs. Use the `OpenAIGenericClient` for these services, which ensures proper schema injection for JSON output since most providers don't support OpenAI's structured output format. When using OpenAI-compatible services, avoid smaller models as they may not accurately extract data or output the correct JSON structures required by Graphiti. Choose larger, more capable models that can handle complex reasoning and structured output. ### Installation ```bash pip install graphiti-core ``` ### Configuration ```python from graphiti_core import Graphiti from graphiti_core.llm_client.openai_generic_client import OpenAIGenericClient from graphiti_core.llm_client.config import LLMConfig from graphiti_core.embedder.openai import OpenAIEmbedder, OpenAIEmbedderConfig from graphiti_core.cross_encoder.openai_reranker_client import OpenAIRerankerClient # Configure OpenAI-compatible service llm_config = LLMConfig( api_key="", model="", # e.g., "mistral-large-latest" small_model="", # e.g., "mistral-small-latest" base_url="", # e.g., "https://api.mistral.ai/v1" ) # Initialize Graphiti with OpenAI-compatible service graphiti = Graphiti( "bolt://localhost:7687", "neo4j", "password", llm_client=OpenAIGenericClient(config=llm_config), embedder=OpenAIEmbedder( config=OpenAIEmbedderConfig( api_key="", embedding_model="", # e.g., "mistral-embed" base_url="", ) ), cross_encoder=OpenAIRerankerClient( config=LLMConfig( api_key="", model="", # Use smaller model for reranking base_url="", ) ) ) ``` Replace the placeholder values with your actual service credentials and model names. # Graph Database Configuration > Configure Neo4j and FalkorDB for Graphiti Graphiti supports two graph database backends: Neo4j and FalkorDB. This guide covers installation and configuration options for both databases across different deployment scenarios. ## Neo4j Neo4j is the primary graph database backend for Graphiti. Version 5.26 or higher is required for full functionality. ### Neo4j Community Edition Neo4j Community Edition is free and suitable for development, testing, and smaller production workloads. #### Installation via Neo4j Desktop The simplest way to install Neo4j is via [Neo4j Desktop](https://neo4j.com/download/), which provides a user-friendly interface to manage Neo4j instances and databases. 1. Download and install Neo4j Desktop 2. Create a new project 3. Add a new database (Local DBMS) 4. Set a password for the `neo4j` user 5. Start the database #### Docker Installation For containerized deployments: ```bash docker run \ --name neo4j-community \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTH=neo4j/your_password \ -e NEO4J_PLUGINS='["apoc"]' \ neo4j:5.26-community ``` #### Configuration Set the following environment variables: ```bash export NEO4J_URI=bolt://localhost:7687 export NEO4J_USER=neo4j export NEO4J_PASSWORD=your_password ``` #### Connection in Python ```python from graphiti_core import Graphiti graphiti = Graphiti( neo4j_uri="bolt://localhost:7687", neo4j_user="neo4j", neo4j_password="your_password" ) ``` ### Neo4j AuraDB (Cloud) Neo4j AuraDB is a fully managed cloud service that handles infrastructure, backups, and updates automatically. #### Setup 1. Sign up for [Neo4j Aura](https://neo4j.com/cloud/platform/aura-graph-database/) 2. Create a new AuraDB instance 3. Note down the connection URI and credentials 4. Download the connection details or copy the connection string #### Configuration AuraDB connections use the `neo4j+s://` protocol for secure connections: ```bash export NEO4J_URI=neo4j+s://your-instance.databases.neo4j.io export NEO4J_USER=neo4j export NEO4J_PASSWORD=your_generated_password ``` #### Connection in Python ```python from graphiti_core import Graphiti graphiti = Graphiti( neo4j_uri="neo4j+s://your-instance.databases.neo4j.io", neo4j_user="neo4j", neo4j_password="your_generated_password" ) ``` AuraDB instances automatically include APOC procedures. No additional configuration is required for most Graphiti operations. ### Neo4j Enterprise Edition Neo4j Enterprise Edition provides advanced features including clustering, hot backups, and performance optimizations. #### Installation Enterprise Edition requires a commercial license. Installation options include: * **Neo4j Desktop**: Add Enterprise Edition license key * **Docker**: Use `neo4j:5.26-enterprise` image with license * **Server Installation**: Download from Neo4j website with valid license #### Docker with Enterprise Features ```bash docker run \ --name neo4j-enterprise \ -p 7474:7474 -p 7687:7687 \ -e NEO4J_AUTH=neo4j/your_password \ -e NEO4J_PLUGINS='["apoc"]' \ -e NEO4J_ACCEPT_LICENSE_AGREEMENT=yes \ neo4j:5.26-enterprise ``` #### Parallel Runtime Configuration Enterprise Edition supports parallel runtime for improved query performance: ```bash export USE_PARALLEL_RUNTIME=true ``` The `USE_PARALLEL_RUNTIME` feature is only available in Neo4j Enterprise Edition and larger AuraDB instances. It is not supported in Community Edition or smaller AuraDB instances. #### Connection in Python ```python import os from graphiti_core import Graphiti # Enable parallel runtime for Enterprise Edition os.environ['USE_PARALLEL_RUNTIME'] = 'true' graphiti = Graphiti( neo4j_uri="bolt://localhost:7687", neo4j_user="neo4j", neo4j_password="your_password" ) ``` ## FalkorDB FalkorDB configuration requires version 1.1.2 or higher. ### Docker Installation The simplest way to run FalkorDB is via Docker: ```bash docker run -p 6379:6379 -p 3000:3000 -it --rm falkordb/falkordb:latest ``` This command: * Exposes FalkorDB on port 6379 (Redis protocol) * Provides a web interface on port 3000 * Runs in foreground mode for easy testing ### Configuration Set the following environment variables for FalkorDB (optional): ```bash export FALKORDB_HOST=localhost # Default: localhost export FALKORDB_PORT=6379 # Default: 6379 export FALKORDB_USERNAME= # Optional: usually not required export FALKORDB_PASSWORD= # Optional: usually not required ``` ### Connection in Python ```python from graphiti_core import Graphiti from graphiti_core.driver.falkordb_driver import FalkorDriver # FalkorDB connection using FalkorDriver falkor_driver = FalkorDriver( host='localhost', # or os.environ.get('FALKORDB_HOST', 'localhost') port='6379', # or os.environ.get('FALKORDB_PORT', '6379') username=None, # or os.environ.get('FALKORDB_USERNAME', None) password=None # or os.environ.get('FALKORDB_PASSWORD', None) ) graphiti = Graphiti(graph_driver=falkor_driver) ``` FalkorDB uses a dedicated `FalkorDriver` and connects via Redis protocol on port 6379. Unlike Neo4j, authentication is typically not required for local FalkorDB instances. # Adding Episodes > How to add data to your Graphiti graph Refer to the [Custom Entity Types](custom-entity-types) page for detailed instructions on adding user-defined ontology to your graph. ### Adding Episodes Episodes represent a single data ingestion event. An `episode` is itself a node, and any nodes identified while ingesting the episode are related to the episode via `MENTIONS` edges. Episodes enable querying for information at a point in time and understanding the provenance of nodes and their edge relationships. Supported episode types: * `text`: Unstructured text data * `message`: Conversational messages of the format `speaker: message...` * `json`: Structured data, processed distinctly from the other types The graph below was generated using the code in the [Quick Start](quick-start). Each **podcast** is an individual episode. ![Simple Graph Visualization](https://raw.githubusercontent.com/getzep/graphiti/main/images/simple_graph.svg) #### Adding a `text` or `message` Episode Using the `EpisodeType.text` type: ```python await graphiti.add_episode( name="tech_innovation_article", episode_body=( "MIT researchers have unveiled 'ClimateNet', an AI system capable of predicting " "climate patterns with unprecedented accuracy. Early tests show it can forecast " "major weather events up to three weeks in advance, potentially revolutionizing " "disaster preparedness and agricultural planning." ), source=EpisodeType.text, # A description of the source (e.g., "podcast", "news article") source_description="Technology magazine article", # The timestamp for when this episode occurred or was created reference_time=datetime(2023, 11, 15, 9, 30), ) ``` Using the `EpisodeType.message` type supports passing in multi-turn conversations in the `episode_body`. The text should be structured in `{role/name}: {message}` pairs. ```python await graphiti.add_episode( name="Customer_Support_Interaction_1", episode_body=( "Customer: Hi, I'm having trouble with my Allbirds shoes. " "The sole is coming off after only 2 months of use.\n" "Support: I'm sorry to hear that. Can you please provide your order number?" ), source=EpisodeType.message, source_description="Customer support chat", reference_time=datetime(2024, 3, 15, 14, 45), ) ``` #### Adding an Episode using structured data in JSON format JSON documents can be arbitrarily nested. However, it's advisable to keep documents compact, as they must fit within your LLM's context window. For large data imports, consider using the `add_episode_bulk` API to efficiently add multiple episodes at once. ```python product_data = { "id": "PROD001", "name": "Men's SuperLight Wool Runners", "color": "Dark Grey", "sole_color": "Medium Grey", "material": "Wool", "technology": "SuperLight Foam", "price": 125.00, "in_stock": True, "last_updated": "2024-03-15T10:30:00Z" } # Add the episode to the graph await graphiti.add_episode( name="Product Update - PROD001", episode_body=product_data, # Pass the Python dictionary directly source=EpisodeType.json, source_description="Allbirds product catalog update", reference_time=datetime.now(), ) ``` #### Loading Episodes in Bulk Graphiti offers `add_episode_bulk` for efficient batch ingestion of episodes, significantly outperforming `add_episode` for large datasets. This method is highly recommended for bulk loading. Use `add_episode_bulk` only for populating empty graphs or when edge invalidation is not required. The bulk ingestion pipeline does not perform edge invalidation operations. ```python product_data = [ { "id": "PROD001", "name": "Men's SuperLight Wool Runners", "color": "Dark Grey", "sole_color": "Medium Grey", "material": "Wool", "technology": "SuperLight Foam", "price": 125.00, "in_stock": true, "last_updated": "2024-03-15T10:30:00Z" }, ... { "id": "PROD0100", "name": "Kids Wool Runner-up Mizzles", "color": "Natural Grey", "sole_color": "Orange", "material": "Wool", "technology": "Water-repellent", "price": 80.00, "in_stock": true, "last_updated": "2024-03-17T14:45:00Z" } ] # Prepare the episodes for bulk loading bulk_episodes = [ RawEpisode( name=f"Product Update - {product['id']}", content=json.dumps(product), source=EpisodeType.json, source_description="Allbirds product catalog update", reference_time=datetime.now() ) for product in product_data ] await graphiti.add_episode_bulk(bulk_episodes) ``` ``` ``` # Custom Entity and Edge Types > Enhancing Graphiti with Custom Ontologies Graphiti allows you to define custom entity types and edge types to better represent your domain-specific knowledge. This enables more structured data extraction and richer semantic relationships in your knowledge graph. ## Defining Custom Entity and Edge Types Custom entity types and edge types are defined using Pydantic models. Each model represents a specific type with custom attributes. ```python from pydantic import BaseModel, Field from datetime import datetime from typing import Optional # Custom Entity Types class Person(BaseModel): """A person entity with biographical information.""" age: Optional[int] = Field(None, description="Age of the person") occupation: Optional[str] = Field(None, description="Current occupation") location: Optional[str] = Field(None, description="Current location") birth_date: Optional[datetime] = Field(None, description="Date of birth") class Company(BaseModel): """A business organization.""" industry: Optional[str] = Field(None, description="Primary industry") founded_year: Optional[int] = Field(None, description="Year company was founded") headquarters: Optional[str] = Field(None, description="Location of headquarters") employee_count: Optional[int] = Field(None, description="Number of employees") class Product(BaseModel): """A product or service.""" category: Optional[str] = Field(None, description="Product category") price: Optional[float] = Field(None, description="Price in USD") release_date: Optional[datetime] = Field(None, description="Product release date") # Custom Edge Types class Employment(BaseModel): """Employment relationship between a person and company.""" position: Optional[str] = Field(None, description="Job title or position") start_date: Optional[datetime] = Field(None, description="Employment start date") end_date: Optional[datetime] = Field(None, description="Employment end date") salary: Optional[float] = Field(None, description="Annual salary in USD") is_current: Optional[bool] = Field(None, description="Whether employment is current") class Investment(BaseModel): """Investment relationship between entities.""" amount: Optional[float] = Field(None, description="Investment amount in USD") investment_type: Optional[str] = Field(None, description="Type of investment (equity, debt, etc.)") stake_percentage: Optional[float] = Field(None, description="Percentage ownership") investment_date: Optional[datetime] = Field(None, description="Date of investment") class Partnership(BaseModel): """Partnership relationship between companies.""" partnership_type: Optional[str] = Field(None, description="Type of partnership") duration: Optional[str] = Field(None, description="Expected duration") deal_value: Optional[float] = Field(None, description="Financial value of partnership") ``` ## Using Custom Entity and Edge Types Pass your custom entity types and edge types to the add\_episode method: ```python entity_types = { "Person": Person, "Company": Company, "Product": Product } edge_types = { "Employment": Employment, "Investment": Investment, "Partnership": Partnership } edge_type_map = { ("Person", "Company"): ["Employment"], ("Company", "Company"): ["Partnership", "Investment"], ("Person", "Person"): ["Partnership"], ("Entity", "Entity"): ["Investment"], # Apply to any entity type } await graphiti.add_episode( name="Business Update", episode_body="Sarah joined TechCorp as CTO in January 2023 with a $200K salary. TechCorp partnered with DataCorp in a $5M deal.", source_description="Business news", reference_time=datetime.now(), entity_types=entity_types, edge_types=edge_types, edge_type_map=edge_type_map ) ``` ## Searching with Custom Types You can filter search results to specific entity types or edge types using SearchFilters: ```python from graphiti_core.search.search_filters import SearchFilters # Search for only specific entity types search_filter = SearchFilters( node_labels=["Person", "Company"] # Only return Person and Company entities ) results = await graphiti.search_( query="Who works at tech companies?", search_filter=search_filter ) # Search for only specific edge types search_filter = SearchFilters( edge_types=["Employment", "Partnership"] # Only return Employment and Partnership edges ) results = await graphiti.search_( query="Tell me about business relationships", search_filter=search_filter ) ``` ## How Custom Types Work ### Entity Extraction Process 1. **Extraction**: Graphiti extracts entities from text and classifies them using your custom types 2. **Validation**: Each entity is validated against the appropriate Pydantic model 3. **Attribute Population**: Custom attributes are extracted from the text and populated 4. **Storage**: Entities are stored with their custom attributes ### Edge Extraction Process 1. **Relationship Detection**: Graphiti identifies relationships between extracted entities 2. **Type Classification**: Based on the entity types involved and your edge\_type\_map, relationships are classified 3. **Attribute Extraction**: For custom edge types, additional attributes are extracted from the context 4. **Validation**: Edge attributes are validated against the Pydantic model 5. **Storage**: Edges are stored with their custom attributes and relationship metadata ## Edge Type Mapping The edge\_type\_map parameter defines which edge types can exist between specific entity type pairs: ```python edge_type_map = { ("Person", "Company"): ["Employment"], ("Company", "Company"): ["Partnership", "Investment"], ("Person", "Person"): ["Partnership"], ("Entity", "Entity"): ["Investment"], # Apply to any entity type } ``` If an entity pair doesn't have a defined edge type mapping, Graphiti will use default relationship types and the relationship will still be captured with a generic RELATES\_TO type. ## Schema Evolution Your knowledge graph's schema can evolve over time as your needs change. You can update entity types by adding new attributes to existing types without breaking existing nodes. When you add new attributes, existing nodes will preserve their original attributes while supporting the new ones for future updates. This flexible approach allows your knowledge graph to grow and adapt while maintaining backward compatibility with historical data. For example, if you initially defined a "Customer" type with basic attributes like name and email, you could later add attributes like "loyalty\_tier" or "acquisition\_channel" without needing to modify or migrate existing customer nodes in your graph. ## Best Practices ### Model Design * **Clear Descriptions**: Always include detailed descriptions in docstrings and Field descriptions * **Optional Fields**: Make custom attributes optional to handle cases where information isn't available * **Appropriate Types**: Use specific types (datetime, int, float) rather than strings when possible * **Validation**: Consider adding Pydantic validators for complex validation rules * **Atomic Attributes**: Attributes should be broken down into their smallest meaningful units rather than storing compound information ```python from pydantic import validator class Person(BaseModel): """A person entity.""" age: Optional[int] = Field(None, description="Age in years") @validator('age') def validate_age(cls, v): if v is not None and (v < 0 or v > 150): raise ValueError('Age must be between 0 and 150') return v ``` **Instead of compound information:** ```python class Customer(BaseModel): contact_info: Optional[str] = Field(None, description="Name and email") # Don't do this ``` **Use atomic attributes:** ```python class Customer(BaseModel): name: Optional[str] = Field(None, description="Customer name") email: Optional[str] = Field(None, description="Customer email address") ``` ### Naming Conventions * **Entity Types**: Use PascalCase (e.g., Person, TechCompany) * **Edge Types**: Use PascalCase for custom types (e.g., Employment, Partnership) * **Attributes**: Use snake\_case (e.g., start\_date, employee\_count) * **Descriptions**: Be specific and actionable for the LLM * **Consistency**: Maintain consistent naming conventions across related entity types ### Edge Type Mapping Strategy * **Specific Mappings**: Define specific entity type pairs for targeted relationships * **Fallback to Entity**: Use ("Entity", "Entity") as a fallback for general relationships * **Balanced Scope**: Don't make edge types too specific or too general * **Domain Coverage**: Ensure your edge types cover the main relationships in your domain ```python # Good: Specific and meaningful edge_type_map = { ("Person", "Company"): ["Employment", "Investment"], ("Company", "Company"): ["Partnership", "Acquisition"], ("Person", "Product"): ["Usage", "Review"], ("Entity", "Entity"): ["RELATES_TO"] # Fallback for unexpected relationships } # Avoid: Too granular edge_type_map = { ("CEO", "TechCompany"): ["CEOEmployment"], ("Engineer", "TechCompany"): ["EngineerEmployment"], # This creates too many specific types } ``` ## Entity Type Exclusion You can exclude specific entity types from extraction using the excluded\_entity\_types parameter: ```python await graphiti.add_episode( name="Business Update", episode_body="The meeting discussed various topics including weather and sports.", source_description="Meeting notes", reference_time=datetime.now(), entity_types=entity_types, excluded_entity_types=["Person"] # Won't extract Person entities ) ``` ## Migration Guide If you're upgrading from a previous version of Graphiti: * You can add entity types to new episodes, even if existing episodes in the graph did not have entity types. Existing nodes will continue to work without being classified. * To add types to previously ingested data, you need to re-ingest it with entity types set into a new graph. ## Important Constraints ### Protected Attribute Names Custom entity type attributes cannot use protected names that are already used by Graphiti's core EntityNode class: * `uuid`, `name`, `group_id`, `labels`, `created_at`, `summary`, `attributes`, `name_embedding` Custom entity types and edge types provide powerful ways to structure your knowledge graph according to your domain needs. They enable more precise extraction, better organization, and richer semantic relationships in your data. # Communities > How to create and update communities In Graphiti, communities (represented as `CommunityNode` objects) represent groups of related entity nodes. Communities can be generated using the `build_communities` method on the graphiti class. ```python await graphiti.build_communities() ``` Communities are determined using the Leiden algorithm, which groups strongly connected nodes together. Communities contain a summary field that collates the summaries held on each of its member entities. This allows Graphiti to provide high-level synthesized information about what the graph contains in addition to the more granular facts stored on edges. Once communities are built, they can also be updated with new episodes by passing in `update_communities=True` to the `add_episode` method. If a new node is added to the graph, we will determine which community it should be added to based on the most represented community of the new node's surrounding nodes. This updating methodology is inspired by the label propagation algorithm for determining communities. However, we still recommend periodically rebuilding communities to ensure the most optimal grouping. Whenever the `build_communities` method is called it will remove any existing communities before creating new ones. # Graph Namespacing > Using group_ids to create isolated graph namespaces ## Overview Graphiti supports the concept of graph namespacing through the use of `group_id` parameters. This feature allows you to create isolated graph environments within the same Graphiti instance, enabling multiple distinct knowledge graphs to coexist without interference. Graph namespacing is particularly useful for: * **Multi-tenant applications**: Isolate data between different customers or organizations * **Testing environments**: Maintain separate development, testing, and production graphs * **Domain-specific knowledge**: Create specialized graphs for different domains or use cases * **Team collaboration**: Allow different teams to work with their own graph spaces ## How Namespacing Works In Graphiti, every node and edge can be associated with a `group_id`. When you specify a `group_id`, you're effectively creating a namespace for that data. Nodes and edges with the same `group_id` form a cohesive, isolated graph that can be queried and manipulated independently from other namespaces. ### Key Benefits * **Data isolation**: Prevent data leakage between different namespaces * **Simplified management**: Organize and manage related data together * **Performance optimization**: Improve query performance by limiting the search space * **Flexible architecture**: Support multiple use cases within a single Graphiti instance ## Using group\_ids in Graphiti ### Adding Episodes with group\_id When adding episodes to your graph, you can specify a `group_id` to namespace the episode and all its extracted entities: ```python await graphiti.add_episode( name="customer_interaction", episode_body="Customer Jane mentioned she loves our new SuperLight Wool Runners in Dark Grey.", source=EpisodeType.text, source_description="Customer feedback", reference_time=datetime.now(), group_id="customer_team" # This namespaces the episode and its entities ) ``` ### Adding Fact Triples with group\_id When manually adding fact triples, ensure both nodes and the edge share the same `group_id`: ```python from graphiti_core.nodes import EntityNode from graphiti_core.edges import EntityEdge import uuid from datetime import datetime # Define a namespace for this data namespace = "product_catalog" # Create source and target nodes with the namespace source_node = EntityNode( uuid=str(uuid.uuid4()), name="SuperLight Wool Runners", group_id=namespace # Apply namespace to source node ) target_node = EntityNode( uuid=str(uuid.uuid4()), name="Sustainable Footwear", group_id=namespace # Apply namespace to target node ) # Create an edge with the same namespace edge = EntityEdge( group_id=namespace, # Apply namespace to edge source_node_uuid=source_node.uuid, target_node_uuid=target_node.uuid, created_at=datetime.now(), name="is_category_of", fact="SuperLight Wool Runners is a product in the Sustainable Footwear category" ) # Add the triplet to the graph await graphiti.add_triplet(source_node, edge, target_node) ``` ### Querying Within a Namespace When querying the graph, specify the `group_id` to limit results to a particular namespace: ```python # Search within a specific namespace search_results = await graphiti.search( query="Wool Runners", group_id="product_catalog" # Only search within this namespace ) # For more advanced node-specific searches, use the _search method with a recipe from graphiti_core.search.search_config_recipes import NODE_HYBRID_SEARCH_RRF # Create a search config for nodes only node_search_config = NODE_HYBRID_SEARCH_RRF.model_copy(deep=True) node_search_config.limit = 5 # Limit to 5 results # Execute the node search within a specific namespace node_search_results = await graphiti._search( query="SuperLight Wool Runners", group_id="product_catalog", # Only search within this namespace config=node_search_config ) ``` ## Best Practices for Graph Namespacing 1. **Consistent naming**: Use a consistent naming convention for your `group_id` values 2. **Documentation**: Maintain documentation of your namespace structure and purpose 3. **Granularity**: Choose an appropriate level of granularity for your namespaces * Too many namespaces can lead to fragmented data * Too few namespaces may not provide sufficient isolation 4. **Cross-namespace queries**: When necessary, perform multiple queries across namespaces and combine results in your application logic ## Example: Multi-tenant Application Here's an example of using namespacing in a multi-tenant application: ```python async def add_customer_data(tenant_id, customer_data): """Add customer data to a tenant-specific namespace""" # Use the tenant_id as the namespace namespace = f"tenant_{tenant_id}" # Create an episode for this customer data await graphiti.add_episode( name=f"customer_data_{customer_data['id']}", episode_body=customer_data, source=EpisodeType.json, source_description="Customer profile update", reference_time=datetime.now(), group_id=namespace # Namespace by tenant ) async def search_tenant_data(tenant_id, query): """Search within a tenant's namespace""" namespace = f"tenant_{tenant_id}" # Only search within this tenant's namespace return await graphiti.search( query=query, group_id=namespace ) ``` # Searching the Graph > How to retrieve information from your Graphiti graph The examples below demonstrate two search approaches in the Graphiti library: 1. **Hybrid Search:** ```python await graphiti.search(query) ``` Combines semantic similarity and BM25 retrieval, reranked using Reciprocal Rank Fusion. Example: Does a broad retrieval of facts related to Allbirds Wool Runners and Jane's purchase. 2. **Node Distance Reranking:** ```python await graphiti.search(query, focal_node_uuid) ``` Extends Hybrid Search above by prioritizing results based on proximity to a specified node in the graph. Example: Focuses on Jane-specific information, highlighting her wool allergy. Node Distance Reranking is particularly useful for entity-specific queries, providing more contextually relevant results. It weights facts by their closeness to the focal node, emphasizing information directly related to the entity of interest. This dual approach allows for both broad exploration and targeted, entity-specific information retrieval from the knowledge graph. ```python query = "Can Jane wear Allbirds Wool Runners?" jane_node_uuid = "123e4567-e89b-12d3-a456-426614174000" def print_facts(edges): print("\n".join([edge.fact for edge in edges])) # Hybrid Search results = await graphiti.search(query) print_facts(results) > The Allbirds Wool Runners are sold by Allbirds. > Men's SuperLight Wool Runners - Dark Grey (Medium Grey Sole) has a runner silhouette. > Jane purchased SuperLight Wool Runners. # Hybrid Search with Node Distance Reranking await client.search(query, jane_node_uuid) print_facts(results) > Jane purchased SuperLight Wool Runners. > Jane is allergic to wool. > The Allbirds Wool Runners are sold by Allbirds. ``` ## Configurable Search Strategies Graphiti also provides a low-level search method that is more configurable than the out-of-the-box search. This search method can be called using `graphiti._search()` and passing in an additional config parameter of type `SearchConfig`. `SearchConfig` contains 4 fields: one for the limit, and three more configs for each of edges, nodes, and communities. The `graphiti._search()` method returns a `SearchResults` object containing a list of nodes, edges, and communities. The `graphiti._search()` method is quite configurable and can be complicated to work with at first. As such, we also have a `search_config_recipes.py` file that contains a few prebuilt `SearchConfig` recipes for common use cases. The 15 recipes are the following: | Search Type | Description | | ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- | | COMBINED\_HYBRID\_SEARCH\_RRF | Performs a hybrid search with RRF reranking over edges, nodes, and communities. | | COMBINED\_HYBRID\_SEARCH\_MMR | Performs a hybrid search with MMR reranking over edges, nodes, and communities. | | COMBINED\_HYBRID\_SEARCH\_CROSS\_ENCODER | Performs a full-text search, similarity search, and BFS with cross\_encoder reranking over edges, nodes, and communities. | | EDGE\_HYBRID\_SEARCH\_RRF | Performs a hybrid search over edges with RRF reranking. | | EDGE\_HYBRID\_SEARCH\_MMR | Performs a hybrid search over edges with MMR reranking. | | EDGE\_HYBRID\_SEARCH\_NODE\_DISTANCE | Performs a hybrid search over edges with node distance reranking. | | EDGE\_HYBRID\_SEARCH\_EPISODE\_MENTIONS | Performs a hybrid search over edges with episode mention reranking. | | EDGE\_HYBRID\_SEARCH\_CROSS\_ENCODER | Performs a hybrid search over edges with cross encoder reranking. | | NODE\_HYBRID\_SEARCH\_RRF | Performs a hybrid search over nodes with RRF reranking. | | NODE\_HYBRID\_SEARCH\_MMR | Performs a hybrid search over nodes with MMR reranking. | | NODE\_HYBRID\_SEARCH\_NODE\_DISTANCE | Performs a hybrid search over nodes with node distance reranking. | | NODE\_HYBRID\_SEARCH\_EPISODE\_MENTIONS | Performs a hybrid search over nodes with episode mentions reranking. | | NODE\_HYBRID\_SEARCH\_CROSS\_ENCODER | Performs a hybrid search over nodes with cross encoder reranking. | | COMMUNITY\_HYBRID\_SEARCH\_RRF | Performs a hybrid search over communities with RRF reranking. | | COMMUNITY\_HYBRID\_SEARCH\_MMR | Performs a hybrid search over communities with MMR reranking. | | COMMUNITY\_HYBRID\_SEARCH\_CROSS\_ENCODER | Performs a hybrid search over communities with cross encoder reranking. | ## Supported Reranking Approaches **Reciprocal Rank Fusion (RRF)** enhances search by combining results from different algorithms, like BM25 and semantic search. Each algorithm's results are ranked, converted to reciprocal scores (1/rank), and summed. This aggregated score determines the final ranking, leveraging the strengths of each method for more accurate retrieval. **Maximal Marginal Relevance (MMR)** is a search strategy that balances relevance and diversity in results. It selects results that are both relevant to the query and diverse from already chosen ones, reducing redundancy and covering different query aspects. MMR ensures comprehensive and varied search results by iteratively choosing results that maximize relevance while minimizing similarity to previously selected results. A **Cross-Encoder** is a model that jointly encodes a query and a result, scoring their relevance by considering their combined context. This approach often yields more accurate results compared to methods that encode query and a text separately. Graphiti supports three cross encoders: * `OpenAIRerankerClient` (the default) - Uses an OpenAI model to classify relevance and the resulting `logprobs` are used to rerank results. * `GeminiRerankerClient` - Uses Google's Gemini models to classify relevance for cost-effective and low-latency reranking. * `BGERerankerClient` - Uses the `BAAI/bge-reranker-v2-m3` model and requires `sentence_transformers` be installed. # CRUD Operations > How to access and modify Nodes and Edges The Graphiti library uses 8 core classes to add data to your graph: * `Node` * `EpisodicNode` * `EntityNode` * `Edge` * `EpisodicEdge` * `EntityEdge` * `CommunityNode` * `CommunityEdge` The generic `Node` and `Edge` classes are abstract base classes, and the other 4 classes inherit from them. Each of `EpisodicNode`, `EntityNode`, `EpisodicEdge`, and `EntityEdge` have fully supported CRUD operations. The save method performs a find or create based on the uuid of the object, and will add or update any other data from the class to the graph. A driver must be provided to the save method. The Entity Node save method is shown below as a sample. ```python async def save(self, driver: AsyncDriver): result = await driver.execute_query( """ MERGE (n:Entity {uuid: $uuid}) SET n = {uuid: $uuid, name: $name, name_embedding: $name_embedding, summary: $summary, created_at: $created_at} RETURN n.uuid AS uuid""", uuid=self.uuid, name=self.name, summary=self.summary, name_embedding=self.name_embedding, created_at=self.created_at, ) logger.info(f'Saved Node to neo4j: {self.uuid}') return result ``` Graphiti also supports hard deleting nodes and edges using the delete method, which also requires a driver. ```python async def delete(self, driver: AsyncDriver): result = await driver.execute_query( """ MATCH (n:Entity {uuid: $uuid}) DETACH DELETE n """, uuid=self.uuid, ) logger.info(f'Deleted Node: {self.uuid}') return result ``` Finally, Graphiti also provides class methods to get nodes and edges by uuid. Note that because these are class methods they are called using the class rather than an instance of the class. ```python async def get_by_uuid(cls, driver: AsyncDriver, uuid: str): records, _, _ = await driver.execute_query( """ MATCH (n:Entity {uuid: $uuid}) RETURN n.uuid As uuid, n.name AS name, n.created_at AS created_at, n.summary AS summary """, uuid=uuid, ) nodes: list[EntityNode] = [] for record in records: nodes.append( EntityNode( uuid=record['uuid'], name=record['name'], labels=['Entity'], created_at=record['created_at'].to_native(), summary=record['summary'], ) ) logger.info(f'Found Node: {uuid}') return nodes[0] ``` # Adding Fact Triples > How to add fact triples to your Graphiti graph A "fact triple" consists of two nodes and an edge between them, where the edge typically contains some fact. You can manually add a fact triple of your choosing to the graph like this: ```python from graphiti_core.nodes import EpisodeType, EntityNode from graphiti_core.edges import EntityEdge import uuid from datetime import datetime source_name = "Bob" target_name = "bananas" source_uuid = "some existing UUID" # This is an existing node, so we use the existing UUID obtained from Neo4j Desktop target_uuid = str(uuid.uuid4()) # This is a new node, so we create a new UUID edge_name = "LIKES" edge_fact = "Bob likes bananas" source_node = EntityNode( uuid=source_uuid, name=source_name, group_id="" ) target_node = EntityNode( uuid=target_uuid, name=target_name, group_id="" ) edge = EntityEdge( group_id="", source_node_uuid=source_uuid, target_node_uuid=target_uuid, created_at=datetime.now(), name=edge_name, fact=edge_fact ) await graphiti.add_triplet(source_node, edge, target_node) ``` When you add a fact triple, Graphiti will attempt to deduplicate your passed in nodes and edge with the already existing nodes and edges in the graph. If there are no duplicates, it will add them as new nodes and edges. Also, you can avoid constructing `EntityEdge` or `EntityNode` objects manually by using the results of a Graphiti search (see [Searching the Graph](/graphiti/graphiti/searching)). # Using LangGraph and Graphiti > Building an agent with LangChain's LangGraph and Graphiti A Jupyter notebook version of this example is available [on GitHub](https://github.com/getzep/graphiti/blob/main/examples/langgraph-agent/agent.ipynb). Looking for a managed Graphiti service? Check out [Zep Cloud](https://www.getzep.com). * Designed as a self-improving memory layer for Agents. * No need to run Neo4j or other dependencies. * Additional features for startups and enterprises alike. * Fast and scalable. The following example demonstrates building an agent using LangGraph. Graphiti is used to personalize agent responses based on information learned from prior conversations. Additionally, a database of products is loaded into the Graphiti graph, enabling the agent to speak to these products. The agent implements: * persistance of new chat turns to Graphiti and recall of relevant Facts using the most recent message. * a tool for querying Graphiti for shoe information * an in-memory `MemorySaver` to maintain agent state. ## Install dependencies ```shell pip install graphiti-core langchain-openai langgraph ipywidgets ``` Ensure that you've followed the [Graphiti installation instructions](installation). In particular, installation of `neo4j`. ```python import asyncio import json import logging import os import sys import uuid from contextlib import suppress from datetime import datetime from pathlib import Path from typing import Annotated import ipywidgets as widgets from dotenv import load_dotenv from IPython.display import Image, display from typing_extensions import TypedDict load_dotenv() ``` ```python def setup_logging(): logger = logging.getLogger() logger.setLevel(logging.ERROR) console_handler = logging.StreamHandler(sys.stdout) console_handler.setLevel(logging.INFO) formatter = logging.Formatter('%(name)s - %(levelname)s - %(message)s') console_handler.setFormatter(formatter) logger.addHandler(console_handler) return logger logger = setup_logging() ``` ## Configure Graphiti Ensure that you have `neo4j` running and a database created. You'll need the following environment variables configured: ```bash NEO4J_URI= NEO4J_USER= NEO4J_PASSWORD= ``` ```python # Configure Graphiti from graphiti_core import Graphiti from graphiti_core.edges import EntityEdge from graphiti_core.nodes import EpisodeType from graphiti_core.utils.bulk_utils import RawEpisode from graphiti_core.utils.maintenance.graph_data_operations import clear_data neo4j_uri = os.environ.get('NEO4J_URI', 'bolt://localhost:7687') neo4j_user = os.environ.get('NEO4J_USER', 'neo4j') neo4j_password = os.environ.get('NEO4J_PASSWORD', 'password') client = Graphiti( neo4j_uri, neo4j_user, neo4j_password, ) ``` ## Generating a database schema The following is only required for the first run of this notebook or when you'd like to start your database over. `clear_data` is destructive and will wipe your entire database. ```python # Note: This will clear the database await clear_data(client.driver) await client.build_indices_and_constraints() ``` ## Load Shoe Data into the Graph Load several shoe and related products into the Graphiti. This may take a while. This only needs to be done once. If you run `clear_data` you'll need to rerun this step. ```python async def ingest_products_data(client: Graphiti): script_dir = Path.cwd().parent json_file_path = script_dir / 'data' / 'manybirds_products.json' with open(json_file_path) as file: products = json.load(file)['products'] episodes: list[RawEpisode] = [ RawEpisode( name=product.get('title', f'Product {i}'), content=str({k: v for k, v in product.items() if k != 'images'}), source_description='ManyBirds products', source=EpisodeType.json, reference_time=datetime.now(), ) for i, product in enumerate(products) ] await client.add_episode_bulk(episodes) await ingest_products_data(client) ``` ## Create a user node in the Graphiti graph In your own app, this step could be done later once the user has identified themselves and made their sales intent known. We do this here so we can configure the agent with the user's `node_uuid`. ```python user_name = 'jess' await client.add_episode( name='User Creation', episode_body=(f'{user_name} is interested in buying a pair of shoes'), source=EpisodeType.text, reference_time=datetime.now(), source_description='SalesBot', ) # let's get Jess's node uuid nl = await client.get_nodes_by_query(user_name) user_node_uuid = nl[0].uuid # and the ManyBirds node uuid nl = await client.get_nodes_by_query('ManyBirds') manybirds_node_uuid = nl[0].uuid ``` ## Helper Functions and LangChain Imports ```python def edges_to_facts_string(entities: list[EntityEdge]): return '-' + '\n- '.join([edge.fact for edge in entities]) ``` ```python from langchain_core.messages import AIMessage, SystemMessage from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.checkpoint.memory import MemorySaver from langgraph.graph import END, START, StateGraph, add_messages from langgraph.prebuilt import ToolNode ``` ## `get_shoe_data` Tool The agent will use this to search the Graphiti graph for information about shoes. We center the search on the `manybirds_node_uuid` to ensure we rank shoe-related data over user data. ```python @tool async def get_shoe_data(query: str) -> str: """Search the graphiti graph for information about shoes""" edge_results = await client.search( query, center_node_uuid=manybirds_node_uuid, num_results=10, ) return edges_to_facts_string(edge_results) tools = [get_shoe_data] tool_node = ToolNode(tools) ``` ## Initialize the LLM and bind tools ```python llm = ChatOpenAI(model='gpt-4o-mini', temperature=0).bind_tools(tools) ``` ### Test the tool node ```python await tool_node.ainvoke({'messages': [await llm.ainvoke('wool shoes')]}) ``` ```json { "messages": [ { "content": "-The product 'Men's SuperLight Wool Runners - Dark Grey (Medium Grey Sole)' is made of Wool.\n- Women's Tree Breezers Knit - Rugged Beige (Hazy Beige Sole) has sizing options related to women's move shoes half sizes.\n- TinyBirds Wool Runners - Little Kids - Natural Black (Blizzard Sole) is a type of Shoes.\n- The product 'Men's SuperLight Wool Runners - Dark Grey (Medium Grey Sole)' belongs to the category Shoes.\n- The product 'Men's SuperLight Wool Runners - Dark Grey (Medium Grey Sole)' uses SuperLight Foam technology.\n- TinyBirds Wool Runners - Little Kids - Natural Black (Blizzard Sole) is sold by Manybirds.\n- Jess is interested in buying a pair of shoes.\n- TinyBirds Wool Runners - Little Kids - Natural Black (Blizzard Sole) has the handle TinyBirds-wool-runners-little-kids.\n- ManyBirds Men's Couriers are a type of Shoes.\n- Women's Tree Breezers Knit - Rugged Beige (Hazy Beige Sole) belongs to the Shoes category.", "name": "get_shoe_data", "tool_call_id": "call_EPpOpD75rdq9jKRBUsfRnfxx" } ] } ``` ## Chatbot Function Explanation The chatbot uses Graphiti to provide context-aware responses in a shoe sales scenario. Here's how it works: 1. **Context Retrieval**: It searches the Graphiti graph for relevant information based on the latest message, using the user's node as the center point. This ensures that user-related facts are ranked higher than other information in the graph. 2. **System Message**: It constructs a system message incorporating facts from Graphiti, setting the context for the AI's response. 3. **Knowledge Persistence**: After generating a response, it asynchronously adds the interaction to the Graphiti graph, allowing future queries to reference this conversation. This approach enables the chatbot to maintain context across interactions and provide personalized responses based on the user's history and preferences stored in the Graphiti graph. ```python class State(TypedDict): messages: Annotated[list, add_messages] user_name: str user_node_uuid: str async def chatbot(state: State): facts_string = None if len(state['messages']) > 0: last_message = state['messages'][-1] graphiti_query = f'{"SalesBot" if isinstance(last_message, AIMessage) else state["user_name"]}: {last_message.content}' # search graphiti using Jess's node uuid as the center node # graph edges (facts) further from the Jess node will be ranked lower edge_results = await client.search( graphiti_query, center_node_uuid=state['user_node_uuid'], num_results=5 ) facts_string = edges_to_facts_string(edge_results) system_message = SystemMessage( content=f"""You are a skillfull shoe salesperson working for ManyBirds. Review information about the user and their prior conversation below and respond accordingly. Keep responses short and concise. And remember, always be selling (and helpful!) Things you'll need to know about the user in order to close a sale: - the user's shoe size - any other shoe needs? maybe for wide feet? - the user's preferred colors and styles - their budget Ensure that you ask the user for the above if you don't already know. Facts about the user and their conversation: {facts_string or 'No facts about the user and their conversation'}""" ) messages = [system_message] + state['messages'] response = await llm.ainvoke(messages) # add the response to the graphiti graph. # this will allow us to use the graphiti search later in the conversation # we're doing async here to avoid blocking the graph execution asyncio.create_task( client.add_episode( name='Chatbot Response', episode_body=f"{state['user_name']}: {state['messages'][-1]}\nSalesBot: {response.content}", source=EpisodeType.message, reference_time=datetime.now(), source_description='Chatbot', ) ) return {'messages': [response]} ``` ## Setting up the Agent This section sets up the Agent's LangGraph graph: 1. **Graph Structure**: It defines a graph with nodes for the agent (chatbot) and tools, connected in a loop. 2. **Conditional Logic**: The `should_continue` function determines whether to end the graph execution or continue to the tools node based on the presence of tool calls. 3. **Memory Management**: It uses a MemorySaver to maintain conversation state across turns. This is in addition to using Graphiti for facts. ```python graph_builder = StateGraph(State) memory = MemorySaver() # Define the function that determines whether to continue or not async def should_continue(state, config): messages = state['messages'] last_message = messages[-1] # If there is no function call, then we finish if not last_message.tool_calls: return 'end' # Otherwise if there is, we continue else: return 'continue' graph_builder.add_node('agent', chatbot) graph_builder.add_node('tools', tool_node) graph_builder.add_edge(START, 'agent') graph_builder.add_conditional_edges('agent', should_continue, {'continue': 'tools', 'end': END}) graph_builder.add_edge('tools', 'agent') graph = graph_builder.compile(checkpointer=memory) ``` Our LangGraph agent graph is illustrated below. ```python with suppress(Exception): display(Image(graph.get_graph().draw_mermaid_png())) ``` ![LangGraph Illustration](file:8e1d2601-303a-4ddc-9d3e-6ff056b05b06) ## Running the Agent Let's test the agent with a single call ```python await graph.ainvoke( { 'messages': [ { 'role': 'user', 'content': 'What sizes do the TinyBirds Wool Runners in Natural Black come in?', } ], 'user_name': user_name, 'user_node_uuid': user_node_uuid, }, config={'configurable': {'thread_id': uuid.uuid4().hex}}, ) ``` ```json { "messages": [ { "content": "What sizes do the TinyBirds Wool Runners in Natural Black come in?", "id": "6a940637-70a0-4c95-a4d7-4c4846909747", "type": "HumanMessage" }, { "content": "The TinyBirds Wool Runners in Natural Black are available in the following sizes for little kids: 5T, 6T, 8T, 9T, and 10T. \n\nDo you have a specific size in mind, or are you looking for something else? Let me know your needs, and I can help you find the perfect pair!", "additional_kwargs": { "refusal": null }, "response_metadata": { "token_usage": { "completion_tokens": 76, "prompt_tokens": 314, "total_tokens": 390 }, "model_name": "gpt-4o-mini-2024-07-18", "system_fingerprint": "fp_f33667828e", "finish_reason": "stop", "logprobs": null }, "id": "run-d2f79c7f-4d41-4896-88dc-476a8e38bea8-0", "usage_metadata": { "input_tokens": 314, "output_tokens": 76, "total_tokens": 390 }, "type": "AIMessage" } ], "user_name": "jess", "user_node_uuid": "186a845eee4849619d1e625b178d1845" } ``` ## Viewing the Graph At this stage, the graph would look something like this. The `jess` node is `INTERESTED_IN` the `TinyBirds Wool Runner` node. The image below was generated using Neo4j Desktop. ![Graph State](file:17dfa33a-dc4e-4db2-b2bf-1d0bdb52273f) ## Running the Agent interactively The following code will run the agent in a Jupyter notebook event loop. You can modify the code to suite your own needs. Just enter a message into the box and click submit. ```python conversation_output = widgets.Output() config = {'configurable': {'thread_id': uuid.uuid4().hex}} user_state = {'user_name': user_name, 'user_node_uuid': user_node_uuid} async def process_input(user_state: State, user_input: str): conversation_output.append_stdout(f'\nUser: {user_input}\n') conversation_output.append_stdout('\nAssistant: ') graph_state = { 'messages': [{'role': 'user', 'content': user_input}], 'user_name': user_state['user_name'], 'user_node_uuid': user_state['user_node_uuid'], } try: async for event in graph.astream( graph_state, config=config, ): for value in event.values(): if 'messages' in value: last_message = value['messages'][-1] if isinstance(last_message, AIMessage) and isinstance( last_message.content, str ): conversation_output.append_stdout(last_message.content) except Exception as e: conversation_output.append_stdout(f'Error: {e}') def on_submit(b): user_input = input_box.value input_box.value = '' asyncio.create_task(process_input(user_state, user_input)) input_box = widgets.Text(placeholder='Type your message here...') submit_button = widgets.Button(description='Send') submit_button.on_click(on_submit) conversation_output.append_stdout('Asssistant: Hello, how can I help you find shoes today?') display(widgets.VBox([input_box, submit_button, conversation_output])) ``` # Telemetry # Telemetry Graphiti collects anonymous usage statistics to help us understand how the framework is being used and improve it for everyone. We believe transparency is important, so here's exactly what we collect and why. ## What We Collect When you initialize a Graphiti instance, we collect: * **Anonymous identifier**: A randomly generated UUID stored locally in `~/.cache/graphiti/telemetry_anon_id` * **System information**: Operating system, Python version, and system architecture * **Graphiti version**: The version you're using * **Configuration choices**: * LLM provider type (OpenAI, Azure, Anthropic, etc.) * Database backend (Neo4j, FalkorDB) * Embedder provider (OpenAI, Azure, Voyage, etc.) ## What We Don't Collect We are committed to protecting your privacy. We **never** collect: * Personal information or identifiers * API keys or credentials * Your actual data, queries, or graph content * IP addresses or hostnames * File paths or system-specific information * Any content from your episodes, nodes, or edges ## Why We Collect This Data This information helps us: * Understand which configurations are most popular to prioritize support and testing * Identify which LLM and database providers to focus development efforts on * Track adoption patterns to guide our roadmap * Ensure compatibility across different Python versions and operating systems By sharing this anonymous information, you help us make Graphiti better for everyone in the community. ## View the Telemetry Code The Telemetry code [may be found here](../graphiti_core/telemetry/telemetry.py). ## How to Disable Telemetry Telemetry is **opt-out** and can be disabled at any time. To disable telemetry collection: ### Option 1: Environment Variable ```bash export GRAPHITI_TELEMETRY_ENABLED=false ``` ### Option 2: Set in your shell profile ```bash # For bash users (~/.bashrc or ~/.bash_profile) echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.bashrc # For zsh users (~/.zshrc) echo 'export GRAPHITI_TELEMETRY_ENABLED=false' >> ~/.zshrc ``` ### Option 3: Set for a specific Python session ```python import os os.environ['GRAPHITI_TELEMETRY_ENABLED'] = 'false' # Then initialize Graphiti as usual from graphiti_core import Graphiti graphiti = Graphiti(...) ``` Telemetry is automatically disabled during test runs (when `pytest` is detected). ## Technical Details * Telemetry uses PostHog for anonymous analytics collection * All telemetry operations are designed to fail silently - they will never interrupt your application or affect Graphiti functionality * The anonymous ID is stored locally and is not tied to any personal information