npm package: @locusgraph/client
Description: TypeScript SDK for LocusGraph memory system with LangChain integration
Author: Nasim Akhtar
Latest version: 0.1.8

# LocusGraph TypeScript SDK

TypeScript/JavaScript SDK for the LocusGraph memory system with seamless LangChain integration.

## Overview

This SDK provides a simple, type-safe interface to interact with LocusGraph's memory system. It supports storing events, retrieving memories with semantic search, generating insights, and integrates seamlessly with LangChain workflows.

## Installation

```bash
npm install @locusgraph/client
# or
yarn add @locusgraph/client
# or
pnpm add @locusgraph/client
```

**Note:** LangChain integration requires peer dependencies:
```bash
npm install @langchain/core langchain
# Optional: for LangChain OpenAI models
npm install @langchain/openai
```

## Quick Start

### Basic Usage

```typescript
import { LocusGraphClient } from '@locusgraph/client';

const client = new LocusGraphClient({
  serverUrl: 'https://api.locusgraph.com',
  agentSecret: 'your-agent-secret',
  graphId: 'default',
});

// Store a memory event
await client.storeEvent({
  graph_id: 'default',
  event_kind: 'fact',
  source: 'agent',
  payload: {
    data: {
      action: 'user_login',
      userId: '123',
      timestamp: new Date().toISOString(),
    },
  },
});

// Retrieve relevant context with semantic search
const context = await client.retrieveMemories({
  graphId: 'default',
  query: 'user authentication patterns',
  limit: 5,
});

console.log(context.memories);
console.log(`Found ${context.items_found} items`);

// Generate insights from stored memories
const insights = await client.generateInsights({
  graphId: 'default',
  task: 'What patterns can we identify in user behavior?',
  locusQuery: 'user actions and authentication',
});

console.log(`Insight: ${insights.insight}`);
console.log(`Confidence: ${insights.confidence}`);
```

### LangChain Integration

#### Using LocusGraph as Memory

```typescript
import { LocusGraphClient, LocusGraphMemory } from '@locusgraph/client';
import { ChatOpenAI } from '@langchain/openai';
import { ConversationChain } from 'langchain/chains';

const client = new LocusGraphClient({
  serverUrl: process.env.LOCUSGRAPH_SERVER_URL,
  agentSecret: process.env.LOCUSGRAPH_AGENT_SECRET,
});
const graphId = 'default';

// Create LocusGraph memory
const memory = new LocusGraphMemory(
  client,
  graphId,  // Required: graph ID
  'my-agent-id',  // Optional: agent ID
  'session-123'  // Optional: session ID
);

// Use with LangChain
const model = new ChatOpenAI({ temperature: 0 });
const chain = new ConversationChain({
  llm: model,
  memory: memory,
});

// First turn - stores in LocusGraph
const response1 = await chain.call({
  input: 'I prefer dark mode for my UI',
});

// Second turn - retrieves context from LocusGraph
const response2 = await chain.call({
  input: 'What did I tell you about my preferences?',
});
```

#### Using LocusGraph as Retriever

```typescript
import { LocusGraphClient, LocusGraphRetriever } from '@locusgraph/client';
import { ChatOpenAI } from '@langchain/openai';
import { RetrievalQAChain } from 'langchain/chains';

const client = new LocusGraphClient({
  serverUrl: process.env.LOCUSGRAPH_SERVER_URL,
  agentSecret: process.env.LOCUSGRAPH_AGENT_SECRET,
});
const graphId = 'default';

// Create LocusGraph retriever
const retriever = new LocusGraphRetriever({
  client,
  graphId,  // Required
  agentId: 'my-agent-id',  // Optional
  limit: 10,  // Optional, default 10
});

// Use with LangChain QA chain
const model = new ChatOpenAI({ temperature: 0 });
const chain = RetrievalQAChain.fromLLM(model, retriever);

const response = await chain.call({
  query: 'What patterns have we learned about security?',
});
```

## API Reference

### LocusGraphClient

Main client for interacting with LocusGraph API.

#### Constructor

```typescript
new LocusGraphClient(config?: LocusGraphConfig)
```

**Config options:**
- `serverUrl?: string` - LocusGraph server URL (default: `https://api.locusgraph.com`)
- `agentSecret?: string` - Agent authentication secret
- `graphId?: string` - Default graph ID for `retrieveMemories`, `listContexts`, and `generateInsights`

#### Methods

##### `storeEvent(request: CreateEventApiRequest): Promise<StoreEventResponse>`

Store a memory event in LocusGraph.

```typescript
const result = await client.storeEvent({
  graph_id: 'default',  // Required
  event_kind: 'fact',  // Required: "fact", "action", "decision", "observation", "feedback"
  source: 'agent',  // Optional: "agent", "user", "system", "validator"
  context_id: 'constraint:file_exists',  // Optional: primary context in format "type:name"
  related_to: ['fact:api_design'],  // Optional: related context IDs
  extends: ['rule:no_nulls'],  // Optional: extended context IDs
  reinforces: ['pattern:react_style'],  // Optional: reinforced context IDs
  contradicts: ['constraint:file_missing'],  // Optional: contradicted context IDs
  payload: {
    data: {
      // Your structured data
      action: 'user_login',
      userId: '123',
    },
  },
  timestamp: '1739697600',  // Optional: Unix timestamp as string
});

// Response
// {
//   event_id: "locus_abc123",
//   status: "recorded",  // "recorded" or "filtered"
//   relevance: "high"  // "high", "medium", or "low"
// }
```

##### `retrieveMemories(query: ContextQuery): Promise<ContextResult>`

Retrieve relevant context from memories using semantic search.

```typescript
const context = await client.retrieveMemories({
  graphId: 'default',  // Optional if set in client config
  query: 'user authentication patterns',  // Required
  limit: 10,  // Optional, default varies
  contextIds: ['fact:api_design', 'rule:no_nulls'],  // Optional: filter by context IDs
  contextTypes: {
    fact: ['api_design', 'user_preferences'],  // Optional: filter by context types
  },
});

// Response
// {
//   memories: "Retrieved memory text...",
//   items_found: 5
// }
```

##### `getContext(params: GetContextParams): Promise<GetContextResponse>`

Get a single context by `context_id` — returns the latest locus payload and metadata (e.g. name, price, available). Throws `Error('Context not found')` when the context is not in the graph.

```typescript
const ctx = await client.getContext({
  graphId: 'default',
  context_id: 'outlet:main',  // type:name format
});
// { context_id, context: { context_type, context_name, ... }, locus_id, payload: { name, price, ... } }
```

##### `listContexts(options?: ListContextsOptions): Promise<ContextTypesResponse | ContextListResponse | ContextSearchResponse>`

List available context types and contexts for filtering.

```typescript
// List all context types
const types = await client.listContexts({
  graphId: 'default',
  limit: 100,
});
// Returns: { context_types: [{ context_type: "fact", count: 42 }], total: 42, page: 0, page_size: 100 }

// List contexts by type
const contexts = await client.listContexts({
  graphId: 'default',
  context_type: 'fact',
  limit: 50,
});
// Returns: { contexts: [{ context_id: "fact:api_design", context_name: "api_design", ... }], ... }

// Search contexts by name
const searchResults = await client.listContexts({
  graphId: 'default',
  context_name: 'api',
  limit: 20,
});
// Returns: { contexts: [...], total: 10, ... }
```

##### `generateInsights(query: InsightQuery): Promise<InsightResult>`

Generate insights from stored memories.

```typescript
const insights = await client.generateInsights({
  graphId: 'default',  // Optional if set in client config
  task: 'What patterns can we identify in user behavior?',  // Required: task/question
  locusQuery: 'user actions and authentication',  // Optional: search query, defaults to task
  limit: 10,  // Optional: max memories to retrieve, default 5
  contextIds: ['fact:api_design'],  // Optional: filter by context IDs
  contextTypes: {
    fact: ['api_design'],  // Optional: filter by context types
  },
});

// Response
// {
//   insight: "Users show a strong preference for dark mode interfaces...",
//   recommendation: "Implement dark mode as default setting",
//   confidence: "high"  // "high", "medium", or "low"
// }
```

### LocusGraphMemory

LangChain memory integration that stores conversations in LocusGraph and automatically classifies event types.

```typescript
const memory = new LocusGraphMemory(
  client: LocusGraphClient,
  graphId: string,  // Required
  agentId?: string,  // Optional
  sessionId?: string  // Optional
);
```

**Memory keys:** `history`, `memories`, `memory_info`

**Automatic event classification:**
- `fact` - Preferences, knowledge, information ("I prefer...", "Remember that...")
- `action` - Completed tasks, operations ("Completed task...", "Did...")
- `decision` - Choices, selections ("Decided to...", "Chose...")
- `observation` - General conversation (default)
- `feedback` - Opinions, ratings, suggestions ("I think...", "Suggest...")

### LocusGraphRetriever

LangChain retriever that queries LocusGraph memories and returns them as LangChain Documents.

```typescript
const retriever = new LocusGraphRetriever({
  client: LocusGraphClient,  // Required
  graphId: string,  // Required
  agentId?: string,  // Optional
  limit?: number,  // Optional, default 10
});
```

Returns `Document[]` with metadata:
- `index` - Document index in results
- `items_found` - Total number of items found
- `agentId` - Agent ID if provided

## Environment Variables

You can configure the client using environment variables:

```bash
LOCUSGRAPH_SERVER_URL=https://api.locusgraph.com
LOCUSGRAPH_AGENT_SECRET=your-agent-secret
```

## Examples

### Code Review Agent

```typescript
import { LocusGraphClient } from '@locusgraph/client';

const client = new LocusGraphClient({ graphId: 'code-review' });

// Store a code review finding
await client.storeEvent({
  graph_id: 'code-review',
  event_kind: 'fact',
  source: 'code_review',
  payload: {
    data: {
      file: 'src/auth.rs',
      pattern: 'raw_sql_in_user_input',
      bugType: 'security',
      severity: 'high',
      fix: 'use_parameterized_queries',
    },
  },
});

// Retrieve similar past reviews
const context = await client.retrieveMemories({
  graphId: 'code-review',
  query: 'SQL injection vulnerability',
  limit: 5,
});

console.log(context.memories);
```

### Research Assistant

```typescript
import { LocusGraphClient, LocusGraphRetriever } from '@locusgraph/client';
import { ChatOpenAI } from '@langchain/openai';
import { RetrievalQAChain } from 'langchain/chains';

const client = new LocusGraphClient({ graphId: 'research' });

// Store a research paper
await client.storeEvent({
  graph_id: 'research',
  event_kind: 'fact',
  payload: {
    data: {
      title: 'Attention Is All You Need',
      concepts: ['transformer', 'attention'],
      keyFindings: ['transformer architecture'],
    },
  },
});

// Use as retriever in LangChain
const retriever = new LocusGraphRetriever({ client, graphId: 'research' });
const chain = RetrievalQAChain.fromLLM(
  new ChatOpenAI(),
  retriever
);

const answer = await chain.call({
  query: 'How do transformers work?',
});
```

### User Preferences Memory

```typescript
import { LocusGraphClient, LocusGraphMemory } from '@locusgraph/client';
import { ChatOpenAI } from '@langchain/openai';
import { ConversationChain } from 'langchain/chains';

const client = new LocusGraphClient({ graphId: 'user-preferences' });
const memory = new LocusGraphMemory(
  client,
  'user-preferences',
  'assistant-bot',
  'user-session-123'
);

const chain = new ConversationChain({
  llm: new ChatOpenAI(),
  memory,
});

// Stores as "fact" automatically
await chain.call({ input: 'I prefer dark mode' });

// Retrieves preferences automatically
await chain.call({ input: 'What are my UI preferences?' });
```

## Event Kinds

LocusGraph supports these event kinds for categorization:

- **fact** - Persistent information, preferences, knowledge
- **action** - Operations, tasks performed, activities
- **decision** - Choices made, selections
- **observation** - General observations, notes
- **feedback** - Opinions, ratings, suggestions

## Context Links

Events can be linked to contexts using:

- `context_id` - Primary context (format: `type:name`)
- `related_to` - Related context IDs
- `extends` - Extended/context detail IDs
- `reinforces` - Reinforced pattern/rule IDs
- `contradicts` - Contradicted constraint IDs

Example:
```typescript
await client.storeEvent({
  graph_id: 'default',
  event_kind: 'fact',
  context_id: 'fact:api_design',
  related_to: ['rule:no_nulls'],
  reinforces: ['pattern:react_style'],
  payload: { data: { message: 'Use nullable types for optional fields' } },
});
```

## TypeScript Support

Full TypeScript support with comprehensive type definitions included. All methods are fully typed for better IDE support and type safety.

## Contact

For graphId and agent tokens, contact: [nasim@effortlesslabs.xyz](mailto:nasim@effortlesslabs.xyz)

Twitter/X: [@fnlog0](https://twitter.com/fnlog0)

## License

MIT