A Go client library for the Graphiti HTTP API.
- Full coverage of Graphiti HTTP API endpoints
- 7 specialized advanced search methods for different query patterns:
- Temporal Window Search - search within time ranges
- Entity Relationships Search - explore entity connections
- Diverse Results Search - get non-redundant results using MMR
- Episode Context Search - search conversation history
- Successful Tools Search - find frequently mentioned techniques
- Recent Context Search - get recent information with recency bias
- Entity By Label Search - filter entities by type/label
- Optional Langfuse observation tracking for monitoring and debugging
- Configurable HTTP client and timeouts
- Type-safe request and response structures
go get github.com/vxcontrol/graphiti-go-clientSee the complete working examples:
- Base Usage Example - Basic operations and common patterns
- Advanced Search Example - All 7 advanced search methods
import (
"time"
graphiti "github.com/vxcontrol/graphiti-go-client"
)
// Create a client with default settings
client := graphiti.NewClient("http://localhost:8000")
// Create a client with custom timeout
client := graphiti.NewClient("http://localhost:8000",
graphiti.WithTimeout(60 * time.Second))
// Create a client with a custom HTTP client
httpClient := &http.Client{
Timeout: 30 * time.Second,
}
client := graphiti.NewClient("http://localhost:8000",
graphiti.WithHTTPClient(httpClient))The client supports optional Langfuse observation tracking for monitoring and debugging. You can attach an Observation object to any of the following operations:
Search- Track search queriesGetMemory- Track memory retrieval operationsAddMessages- Track message ingestionAddEntityNode- Track entity node creation
Observation.ID and Observation.TraceID must be valid UUIDs that correspond to actual observation and trace objects in your Langfuse instance. These IDs are used to link Graphiti operations to Langfuse traces for monitoring and debugging.
Example:
import "github.com/google/uuid"
// Create an observation with UUIDs that exist in Langfuse
// These IDs should come from your Langfuse SDK after creating
// an observation/trace in your Langfuse instance
observation := &graphiti.Observation{
ID: "existing-observation-uuid-from-langfuse",
TraceID: "existing-trace-uuid-from-langfuse",
Time: time.Now(),
}
// Use it in any supported operation
result, err := client.Search(graphiti.SearchQuery{
Query: "my search query",
MaxFacts: 10,
Observation: observation,
})The observation tracking is completely optional - all operations work without it.
health, err := client.HealthCheck()
if err != nil {
log.Fatal(err)
}
fmt.Printf("Status: %s\n", health.Status)result, err := client.Search(graphiti.SearchQuery{
Query: "Tell me about user preferences",
MaxFacts: 10,
})
if err != nil {
log.Fatal(err)
}
for _, fact := range result.Facts {
fmt.Printf("Fact: %s\n", fact.Fact)
}groupIDs := []string{"group-123", "group-456"}
// Optional: Link to existing Langfuse observation
// IDs must correspond to actual observation/trace in Langfuse
observation := &graphiti.Observation{
ID: "existing-observation-uuid",
TraceID: "existing-trace-uuid",
Time: time.Now(),
}
result, err := client.Search(graphiti.SearchQuery{
GroupIDs: &groupIDs,
Query: "user settings",
MaxFacts: 5,
Observation: observation, // Optional
})/messages endpoint is asynchronous. Messages are queued and processed by a background worker. Data may not be immediately available after this call returns.
messages := []graphiti.Message{
{
Content: "Hello, how are you?",
Author: "User",
Timestamp: time.Now(),
},
{
Content: "I'm doing great, thank you!",
Author: "Assistant",
Timestamp: time.Now(),
},
}
// Optional: Link to existing Langfuse observation
// IDs must correspond to actual observation/trace in Langfuse
observation := &graphiti.Observation{
ID: "existing-observation-uuid",
TraceID: "existing-trace-uuid",
Time: time.Now(),
}
result, err := client.AddMessages(graphiti.AddMessagesRequest{
GroupID: "my-group-id",
Messages: messages,
Observation: observation, // Optional
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s: %v\n", result.Message, result.Success)
// Wait for processing by polling for episodes
maxAttempts := 10
for attempt := 1; attempt <= maxAttempts; attempt++ {
episodes, err := client.GetEpisodes("my-group-id", 10)
if err == nil && len(episodes) > 0 {
fmt.Println("Messages processed successfully!")
break
}
time.Sleep(5 * time.Second)
}uuid := "entity-uuid-123"
// Optional: Link to existing Langfuse observation
// IDs must correspond to actual observation/trace in Langfuse
observation := &graphiti.Observation{
ID: "existing-observation-uuid",
TraceID: "existing-trace-uuid",
Time: time.Now(),
}
node, err := client.AddEntityNode(graphiti.AddEntityNodeRequest{
UUID: uuid,
GroupID: "my-group-id",
Name: "User Preferences",
Summary: "Contains user's preferred settings",
Observation: observation, // Optional
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Created node: %s\n", node.UUID)messages := []graphiti.Message{
{
Content: "What were my settings?",
Author: "User",
Timestamp: time.Now(),
},
}
// Optional: Link to existing Langfuse observation
// IDs must correspond to actual observation/trace in Langfuse
observation := &graphiti.Observation{
ID: "existing-observation-uuid",
TraceID: "existing-trace-uuid",
Time: time.Now(),
}
response, err := client.GetMemory(graphiti.GetMemoryRequest{
GroupID: "my-group-id",
MaxFacts: 10,
Messages: messages,
Observation: observation, // Optional
})
if err != nil {
log.Fatal(err)
}
for _, fact := range response.Facts {
fmt.Printf("Fact: %s (from %s)\n", fact.Fact, fact.Name)
}episodes, err := client.GetEpisodes("my-group-id", 5)
if err != nil {
log.Fatal(err)
}
for _, episode := range episodes {
fmt.Printf("Episode: %s - %s\n", episode.Name, episode.Content)
}fact, err := client.GetEntityEdge("edge-uuid-123")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Fact: %s\n", fact.Fact)The client provides specialized search methods for different use cases:
Search for context within a specific time window:
result, err := client.TemporalWindowSearch(graphiti.TemporalSearchRequest{
Query: "user activities",
GroupID: &groupID,
TimeStart: time.Now().Add(-24 * time.Hour),
TimeEnd: time.Now(),
MaxResults: 10,
})
if err != nil {
log.Fatal(err)
}
fmt.Printf("Found %d edges, %d nodes, %d episodes\n",
len(result.Edges), len(result.Nodes), len(result.Episodes))Find relationships and related entities from a center node:
result, err := client.EntityRelationshipsSearch(graphiti.EntityRelationshipSearchRequest{
Query: "related entities",
GroupID: &groupID,
CenterNodeUUID: "entity-uuid-123",
MaxDepth: 2,
NodeLabels: &[]string{"PERSON", "ORGANIZATION"},
MaxResults: 20,
})Get diverse, non-redundant results using Maximal Marginal Relevance (MMR):
result, err := client.DiverseResultsSearch(graphiti.DiverseSearchRequest{
Query: "user interests and hobbies",
GroupID: &groupID,
DiversityLevel: "medium", // "low", "medium", or "high"
MaxResults: 10,
})Search through agent responses and conversation context:
result, err := client.EpisodeContextSearch(graphiti.EpisodeContextSearchRequest{
Query: "tool execution results",
GroupID: &groupID,
MaxResults: 5,
})Find frequently mentioned successful tools or techniques:
result, err := client.SuccessfulToolsSearch(graphiti.SuccessfulToolsSearchRequest{
Query: "successful exploits",
GroupID: &groupID,
MinMentions: 2,
MaxResults: 10,
})Get most recent relevant context with recency bias:
result, err := client.RecentContextSearch(graphiti.RecentContextSearchRequest{
Query: "recent discoveries",
GroupID: &groupID,
RecencyWindow: "6h", // e.g., "1h", "24h", "7d"
MaxResults: 10,
})Search for entities by their labels/types:
result, err := client.EntityByLabelSearch(graphiti.EntityByLabelSearchRequest{
Query: "vulnerable services",
GroupID: &groupID,
NodeLabels: []string{"SERVICE", "VULNERABILITY"},
MaxResults: 20,
})// Delete an entity edge
result, err := client.DeleteEntityEdge("edge-uuid-123")
// Delete an episode
result, err := client.DeleteEpisode("episode-uuid-123")
// Delete a group
result, err := client.DeleteGroup("group-id-123")
// Clear all data (use with caution!)
result, err := client.Clear()type Observation struct {
ID string // Observation UUID from Langfuse
TraceID string // Trace UUID from Langfuse
Time time.Time // Observation timestamp
}Note: The Observation type is used for integrating with Langfuse for tracking and observability. The ID and TraceID must be valid UUIDs corresponding to actual observation and trace objects in your Langfuse instance. This field is optional in all requests.
type Message struct {
Content string // The message content
UUID *string // Optional UUID
Name string // Optional name for episodic node
Author string // The author/entity that created this message
Timestamp time.Time // Message timestamp
SourceDescription string // Optional source description
}type SearchQuery struct {
GroupIDs *[]string // Optional group IDs to filter
Query string // Search query text
MaxFacts int // Maximum number of facts to return (default: 10)
Observation *Observation // Optional Langfuse observation for tracking
}type FactResult struct {
UUID string // Unique identifier
Name string // Fact name
Fact string // The actual fact text
ValidAt *time.Time // When fact became valid
InvalidAt *time.Time // When fact became invalid
CreatedAt time.Time // Creation timestamp
ExpiredAt *time.Time // Expiration timestamp
}type GetMemoryRequest struct {
GroupID string // Group ID
MaxFacts int // Maximum number of facts to return
CenterNodeUUID *string // Optional center node UUID
Messages []Message // Messages for context
Observation *Observation // Optional Langfuse observation for tracking
}type AddMessagesRequest struct {
GroupID string // Group ID
Messages []Message // Messages to add
Observation *Observation // Optional Langfuse observation for tracking
}type AddEntityNodeRequest struct {
UUID string // Entity UUID
GroupID string // Group ID
Name string // Entity name
Summary string // Optional entity summary
Observation *Observation // Optional Langfuse observation for tracking
}type NodeResult struct {
UUID string // Node UUID
Name string // Entity name
Labels []string // Entity type labels (e.g., ["SERVICE", "WEB"])
Summary string // Node summary/description
CreatedAt time.Time // Creation timestamp
}type EdgeResult struct {
UUID string // Edge UUID
Name string // Relationship name
Fact string // The fact/relationship description
SourceNodeUUID string // Source entity UUID
TargetNodeUUID string // Target entity UUID
ValidAt *time.Time // When relationship became valid
InvalidAt *time.Time // When relationship became invalid
CreatedAt time.Time // Creation timestamp
ExpiredAt *time.Time // Expiration timestamp
}type EpisodeResult struct {
UUID string // Episode UUID
Content string // Episode content (agent response, tool output, etc.)
Source string // Source type (e.g., "tool", "agent")
SourceDescription string // Detailed source description
CreatedAt time.Time // Creation timestamp
ValidAt time.Time // When episode occurred
}type CommunityResult struct {
UUID string // Community UUID
Name string // Community name
Summary string // Community summary
CreatedAt time.Time // Creation timestamp
}All client methods return an error as the last return value. Always check for errors:
result, err := client.Search(query)
if err != nil {
// Handle error
log.Printf("Search failed: %v", err)
return
}
// Use resultTwo complete working examples are available:
Demonstrates basic operations:
- Client initialization and health checks
- Adding messages with Langfuse observation tracking
- Basic search and memory retrieval
- Entity node creation
- Episode management
- Proper handling of asynchronous operations
Comprehensive demonstration of all 7 advanced search methods:
- Temporal Window Search - query within specific time ranges
- Entity Relationships Search - explore entity connections and graph traversal
- Diverse Results Search - get non-redundant results using MMR
- Episode Context Search - search through conversation history and tool outputs
- Successful Tools Search - find frequently mentioned successful techniques
- Recent Context Search - retrieve recent information with recency bias
- Entity By Label Search - filter entities by type/label
This example uses a realistic penetration testing scenario with detailed test data to demonstrate each search method's capabilities.