@memorylayerai/sdk 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -28,11 +28,42 @@ yarn add @memorylayerai/sdk
28
28
 
29
29
  ## Quick Start
30
30
 
31
- ### 1. Get Your API Key
31
+ ### Option 1: Transparent Router (Zero Code Changes) ⚡
32
+
33
+ The easiest way to add memory - just change your OpenAI baseURL:
34
+
35
+ ```typescript
36
+ import OpenAI from 'openai';
37
+
38
+ const openai = new OpenAI({
39
+ baseURL: 'https://api.memorylayer.ai/v1', // ← Just change this
40
+ apiKey: 'ml_your_memorylayer_key' // ← Use your MemoryLayer key
41
+ });
42
+
43
+ // That's it! Memory is automatically injected
44
+ const response = await openai.chat.completions.create({
45
+ model: 'gpt-4',
46
+ messages: [{ role: 'user', content: 'What are my preferences?' }]
47
+ });
48
+ ```
49
+
50
+ **Benefits:**
51
+ - ✅ Zero code changes to your application
52
+ - ✅ Automatic memory injection
53
+ - ✅ Works with existing OpenAI SDK code
54
+ - ✅ Configurable via headers
55
+
56
+ See [Transparent Router Guide](#transparent-router) for details.
57
+
58
+ ### Option 2: Manual Integration (Full Control)
59
+
60
+ For more control over memory retrieval and injection:
61
+
62
+ #### 1. Get Your API Key
32
63
 
33
64
  Sign up at [memorylayer.com](https://memorylayer.com) and create an API key from your project settings.
34
65
 
35
- ### 2. Initialize the Client
66
+ #### 2. Initialize the Client
36
67
 
37
68
  ```typescript
38
69
  import { MemoryLayer } from '@memorylayerai/sdk';
@@ -44,7 +75,7 @@ const client = new MemoryLayer({
44
75
  });
45
76
  ```
46
77
 
47
- ### 3. Create Memories
78
+ #### 3. Create Memories
48
79
 
49
80
  ```typescript
50
81
  // Create a single memory
@@ -61,7 +92,7 @@ const memory = await client.memories.create({
61
92
  console.log('Memory created:', memory.id);
62
93
  ```
63
94
 
64
- ### 4. Search Memories
95
+ #### 4. Search Memories
65
96
 
66
97
  ```typescript
67
98
  // Hybrid search (vector + keyword + graph)
@@ -82,6 +113,124 @@ results.forEach(result => {
82
113
  });
83
114
  ```
84
115
 
116
+ ## Transparent Router
117
+
118
+ The transparent router is an OpenAI-compatible proxy that automatically injects memory context into your requests. It's the easiest way to add memory to your application.
119
+
120
+ ### Basic Usage
121
+
122
+ ```typescript
123
+ import OpenAI from 'openai';
124
+
125
+ const openai = new OpenAI({
126
+ baseURL: 'https://api.memorylayer.ai/v1',
127
+ apiKey: process.env.MEMORYLAYER_API_KEY
128
+ });
129
+
130
+ const response = await openai.chat.completions.create({
131
+ model: 'gpt-4',
132
+ messages: [{ role: 'user', content: 'What are my preferences?' }]
133
+ });
134
+ ```
135
+
136
+ ### Configuration Headers
137
+
138
+ Control memory injection with optional headers:
139
+
140
+ ```typescript
141
+ const response = await openai.chat.completions.create({
142
+ model: 'gpt-4',
143
+ messages: [{ role: 'user', content: 'Hello!' }],
144
+ headers: {
145
+ 'x-memory-user-id': 'user_123', // User scope
146
+ 'x-memory-session-id': 'sess_abc', // Session scope
147
+ 'x-memory-limit': '10', // Max memories
148
+ 'x-memory-injection-mode': 'balanced', // safe|balanced|full
149
+ 'x-memory-injection-strategy': 'system_append', // Injection strategy
150
+ 'x-memory-disabled': 'false' // Enable/disable
151
+ }
152
+ });
153
+ ```
154
+
155
+ ### Injection Modes
156
+
157
+ - **safe**: Only fact + preference (minimal risk)
158
+ - **balanced** (default): fact + preference + trusted summaries
159
+ - **full**: All memory types including snippets
160
+
161
+ ### Diagnostic Headers
162
+
163
+ Every response includes diagnostic headers:
164
+
165
+ ```typescript
166
+ const response = await openai.chat.completions.create({ ... });
167
+
168
+ console.log('Memories retrieved:', response.headers?.['x-memory-hit-count']);
169
+ console.log('Tokens injected:', response.headers?.['x-memory-injected-tokens']);
170
+ console.log('Max score:', response.headers?.['x-memory-max-score']);
171
+ console.log('Query rewriting:', response.headers?.['x-memory-rewrite']);
172
+ console.log('Memory status:', response.headers?.['x-memory-status']);
173
+ console.log('Session ID:', response.headers?.['x-memory-session-id']);
174
+ ```
175
+
176
+ ### Streaming Support
177
+
178
+ Streaming works seamlessly:
179
+
180
+ ```typescript
181
+ const stream = await openai.chat.completions.create({
182
+ model: 'gpt-4',
183
+ messages: [{ role: 'user', content: 'Tell me about myself' }],
184
+ stream: true,
185
+ headers: {
186
+ 'x-memory-user-id': 'user_123'
187
+ }
188
+ });
189
+
190
+ for await (const chunk of stream) {
191
+ const content = chunk.choices[0]?.delta?.content || '';
192
+ process.stdout.write(content);
193
+ }
194
+ ```
195
+
196
+ ### Session Management
197
+
198
+ If you don't provide `x-memory-user-id` or `x-memory-session-id`, the router generates a session ID. Persist it for conversation continuity:
199
+
200
+ ```typescript
201
+ const response = await openai.chat.completions.create({ ... });
202
+
203
+ // Get generated session ID
204
+ const sessionId = response.headers?.['x-memory-session-id'];
205
+
206
+ // Store it and send on next request
207
+ const nextResponse = await openai.chat.completions.create({
208
+ messages: [...],
209
+ headers: {
210
+ 'x-memory-session-id': sessionId // ← Persist this!
211
+ }
212
+ });
213
+ ```
214
+
215
+ ### Error Handling
216
+
217
+ The router gracefully degrades on errors:
218
+
219
+ ```typescript
220
+ const response = await openai.chat.completions.create({ ... });
221
+
222
+ // Check memory status
223
+ const memoryStatus = response.headers?.['x-memory-status'];
224
+ if (memoryStatus === 'error') {
225
+ console.warn('Memory retrieval failed:', response.headers?.['x-memory-error-code']);
226
+ console.log('But the request still succeeded (graceful degradation)');
227
+ }
228
+ ```
229
+
230
+ ### Migration from Manual Integration
231
+
232
+ See [examples/MIGRATION_GUIDE.md](../../examples/MIGRATION_GUIDE.md) for a complete migration guide.
233
+
85
234
  ## Core Features
86
235
 
87
236
  ### Memory Management
package/dist/index.cjs CHANGED
@@ -414,11 +414,197 @@ var init_router = __esm({
414
414
  }
415
415
  });
416
416
 
417
+ // src/resources/graph.ts
418
+ var graph_exports = {};
419
+ __export(graph_exports, {
420
+ GraphResource: () => GraphResource
421
+ });
422
+ var GraphResource;
423
+ var init_graph = __esm({
424
+ "src/resources/graph.ts"() {
425
+ "use strict";
426
+ init_errors();
427
+ GraphResource = class {
428
+ constructor(httpClient) {
429
+ this.httpClient = httpClient;
430
+ }
431
+ /**
432
+ * Get graph data for a space/project
433
+ *
434
+ * Fetches nodes (memories, documents, entities) and edges (relationships)
435
+ * for visualization. Supports pagination and filtering.
436
+ *
437
+ * @param request - Graph data request with filters
438
+ * @returns Graph data with nodes, edges, metadata, and pagination
439
+ *
440
+ * @example
441
+ * ```typescript
442
+ * const graphData = await client.graph.getGraph({
443
+ * spaceId: 'project-123',
444
+ * limit: 100,
445
+ * nodeTypes: ['memory', 'document'],
446
+ * relationshipTypes: ['extends', 'updates']
447
+ * });
448
+ *
449
+ * console.log(`Found ${graphData.nodes.length} nodes`);
450
+ * console.log(`Found ${graphData.edges.length} edges`);
451
+ * ```
452
+ *
453
+ * Requirements: 6.1
454
+ */
455
+ async getGraph(request) {
456
+ if (!request.spaceId || request.spaceId.trim().length === 0) {
457
+ throw new ValidationError(
458
+ "Space ID is required",
459
+ [{ field: "spaceId", message: "Space ID is required" }]
460
+ );
461
+ }
462
+ const query = {};
463
+ if (request.cursor) {
464
+ query.cursor = request.cursor;
465
+ }
466
+ if (request.limit !== void 0) {
467
+ query.limit = request.limit.toString();
468
+ }
469
+ if (request.nodeTypes && request.nodeTypes.length > 0) {
470
+ query.nodeTypes = request.nodeTypes.join(",");
471
+ }
472
+ if (request.relationshipTypes && request.relationshipTypes.length > 0) {
473
+ query.relationshipTypes = request.relationshipTypes.join(",");
474
+ }
475
+ if (request.startDate) {
476
+ query.startDate = request.startDate;
477
+ }
478
+ if (request.endDate) {
479
+ query.endDate = request.endDate;
480
+ }
481
+ return this.httpClient.request({
482
+ method: "GET",
483
+ path: `/v1/graph/spaces/${request.spaceId}`,
484
+ query
485
+ });
486
+ }
487
+ /**
488
+ * Get detailed information for a specific node
489
+ *
490
+ * Fetches node data, connected edges, and neighboring nodes.
491
+ *
492
+ * @param request - Node details request
493
+ * @returns Node details with edges and connected nodes
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const details = await client.graph.getNodeDetails({
498
+ * nodeId: 'memory-456'
499
+ * });
500
+ *
501
+ * console.log(`Node: ${details.node.label}`);
502
+ * console.log(`Connected to ${details.connectedNodes.length} nodes`);
503
+ * ```
504
+ *
505
+ * Requirements: 6.2
506
+ */
507
+ async getNodeDetails(request) {
508
+ if (!request.nodeId || request.nodeId.trim().length === 0) {
509
+ throw new ValidationError(
510
+ "Node ID is required",
511
+ [{ field: "nodeId", message: "Node ID is required" }]
512
+ );
513
+ }
514
+ return this.httpClient.request({
515
+ method: "GET",
516
+ path: `/v1/graph/nodes/${request.nodeId}`
517
+ });
518
+ }
519
+ /**
520
+ * Get edges connected to a specific node
521
+ *
522
+ * Fetches edges and connected nodes, optionally filtered by edge type.
523
+ *
524
+ * @param request - Node edges request
525
+ * @returns Edges and connected nodes
526
+ *
527
+ * @example
528
+ * ```typescript
529
+ * const edges = await client.graph.getNodeEdges({
530
+ * nodeId: 'memory-456',
531
+ * edgeTypes: ['extends', 'updates']
532
+ * });
533
+ *
534
+ * console.log(`Found ${edges.edges.length} edges`);
535
+ * ```
536
+ *
537
+ * Requirements: 6.3
538
+ */
539
+ async getNodeEdges(request) {
540
+ if (!request.nodeId || request.nodeId.trim().length === 0) {
541
+ throw new ValidationError(
542
+ "Node ID is required",
543
+ [{ field: "nodeId", message: "Node ID is required" }]
544
+ );
545
+ }
546
+ const query = {};
547
+ if (request.edgeTypes && request.edgeTypes.length > 0) {
548
+ query.edgeTypes = request.edgeTypes.join(",");
549
+ }
550
+ return this.httpClient.request({
551
+ method: "GET",
552
+ path: `/v1/graph/nodes/${request.nodeId}/edges`,
553
+ query
554
+ });
555
+ }
556
+ /**
557
+ * Get all graph pages using async iteration
558
+ *
559
+ * Automatically handles pagination to fetch all nodes and edges.
560
+ * Yields each page of results as they are fetched.
561
+ *
562
+ * @param request - Initial graph request (without cursor)
563
+ * @yields Graph data for each page
564
+ *
565
+ * @example
566
+ * ```typescript
567
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
568
+ * console.log(`Page has ${page.nodes.length} nodes`);
569
+ * // Process nodes...
570
+ * }
571
+ * ```
572
+ *
573
+ * @example
574
+ * ```typescript
575
+ * // Collect all nodes
576
+ * const allNodes: GraphNode[] = [];
577
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
578
+ * allNodes.push(...page.nodes);
579
+ * }
580
+ * console.log(`Total nodes: ${allNodes.length}`);
581
+ * ```
582
+ *
583
+ * Requirements: 6.4
584
+ */
585
+ async *getAllGraphPages(request) {
586
+ let cursor;
587
+ let hasMore = true;
588
+ while (hasMore) {
589
+ const page = await this.getGraph({
590
+ ...request,
591
+ cursor
592
+ });
593
+ yield page;
594
+ cursor = page.pagination.nextCursor;
595
+ hasMore = page.pagination.hasMore;
596
+ }
597
+ }
598
+ };
599
+ }
600
+ });
601
+
417
602
  // src/index.ts
418
603
  var index_exports = {};
419
604
  __export(index_exports, {
420
605
  APIError: () => APIError,
421
606
  AuthenticationError: () => AuthenticationError,
607
+ GraphResource: () => GraphResource,
422
608
  IngestResource: () => IngestResource,
423
609
  MemoriesResource: () => MemoriesResource,
424
610
  MemoryLayerClient: () => MemoryLayerClient,
@@ -704,6 +890,16 @@ var MemoryLayerClient = class {
704
890
  }
705
891
  return this._router;
706
892
  }
893
+ /**
894
+ * Access graph visualization operations
895
+ */
896
+ get graph() {
897
+ if (!this._graph) {
898
+ const { GraphResource: GraphResource2 } = (init_graph(), __toCommonJS(graph_exports));
899
+ this._graph = new GraphResource2(this.httpClient);
900
+ }
901
+ return this._graph;
902
+ }
707
903
  };
708
904
 
709
905
  // src/index.ts
@@ -712,10 +908,12 @@ init_memories();
712
908
  init_search();
713
909
  init_ingest();
714
910
  init_router();
911
+ init_graph();
715
912
  // Annotate the CommonJS export names for ESM import in node:
716
913
  0 && (module.exports = {
717
914
  APIError,
718
915
  AuthenticationError,
916
+ GraphResource,
719
917
  IngestResource,
720
918
  MemoriesResource,
721
919
  MemoryLayerClient,
package/dist/index.d.cts CHANGED
@@ -31,6 +31,7 @@ declare class MemoryLayerClient {
31
31
  private _search?;
32
32
  private _ingest?;
33
33
  private _router?;
34
+ private _graph?;
34
35
  constructor(config?: ClientConfig$1);
35
36
  /**
36
37
  * Access memory operations
@@ -48,6 +49,10 @@ declare class MemoryLayerClient {
48
49
  * Access router operations
49
50
  */
50
51
  get router(): any;
52
+ /**
53
+ * Access graph visualization operations
54
+ */
55
+ get graph(): any;
51
56
  }
52
57
 
53
58
  /**
@@ -308,6 +313,171 @@ interface StreamChunk {
308
313
  /** Array of streaming choices */
309
314
  choices: StreamChoice[];
310
315
  }
316
+ /**
317
+ * Memory status for visualization
318
+ */
319
+ type MemoryStatus = 'latest' | 'older' | 'forgotten' | 'expiring' | 'new';
320
+ /**
321
+ * Node types in the graph
322
+ */
323
+ type NodeType = 'memory' | 'document' | 'entity';
324
+ /**
325
+ * Edge types in the graph
326
+ */
327
+ type EdgeType = 'updates' | 'extends' | 'derives' | 'similarity';
328
+ /**
329
+ * Node in the graph (memory, document, or entity)
330
+ */
331
+ interface GraphNode {
332
+ /** Unique identifier for the node */
333
+ id: string;
334
+ /** Type of node */
335
+ type: NodeType;
336
+ /** Display label (truncated content or title) */
337
+ label: string;
338
+ /** Node data */
339
+ data: {
340
+ /** Full content (for memory nodes) */
341
+ content?: string;
342
+ /** Title (for document nodes) */
343
+ title?: string;
344
+ /** Memory status */
345
+ status?: MemoryStatus;
346
+ /** Creation timestamp (ISO 8601) */
347
+ createdAt: string;
348
+ /** Expiration timestamp (ISO 8601) */
349
+ expiresAt?: string;
350
+ /** Source reference */
351
+ source?: string;
352
+ /** Additional metadata */
353
+ metadata?: Record<string, any>;
354
+ };
355
+ /** Optional position hints for layout */
356
+ position?: {
357
+ x: number;
358
+ y: number;
359
+ };
360
+ }
361
+ /**
362
+ * Edge in the graph (relationship or similarity)
363
+ */
364
+ interface GraphEdge {
365
+ /** Unique identifier for the edge */
366
+ id: string;
367
+ /** Source node ID */
368
+ source: string;
369
+ /** Target node ID */
370
+ target: string;
371
+ /** Type of edge */
372
+ type: EdgeType;
373
+ /** Display label for the edge */
374
+ label?: string;
375
+ /** Edge data */
376
+ data: {
377
+ /** Strength of the relationship (0.0 to 1.0) */
378
+ strength: number;
379
+ /** Additional metadata */
380
+ metadata?: Record<string, any>;
381
+ };
382
+ }
383
+ /**
384
+ * Graph metadata and statistics
385
+ */
386
+ interface GraphMetadata {
387
+ /** Total number of nodes */
388
+ totalNodes: number;
389
+ /** Number of memory nodes */
390
+ memoryCount: number;
391
+ /** Number of document nodes */
392
+ documentCount: number;
393
+ /** Number of entity nodes */
394
+ entityCount: number;
395
+ /** Total number of edges */
396
+ totalEdges: number;
397
+ /** Number of relationship edges */
398
+ relationshipCount: number;
399
+ /** Number of similarity edges */
400
+ similarityCount: number;
401
+ }
402
+ /**
403
+ * Pagination information
404
+ */
405
+ interface PaginationInfo {
406
+ /** Whether there are more results */
407
+ hasMore: boolean;
408
+ /** Cursor for the next page */
409
+ nextCursor?: string;
410
+ /** Total count (optional, may be expensive to compute) */
411
+ totalCount?: number;
412
+ }
413
+ /**
414
+ * Complete graph data structure
415
+ */
416
+ interface GraphData {
417
+ /** Array of nodes */
418
+ nodes: GraphNode[];
419
+ /** Array of edges */
420
+ edges: GraphEdge[];
421
+ /** Graph metadata and statistics */
422
+ metadata: GraphMetadata;
423
+ /** Pagination information */
424
+ pagination: PaginationInfo;
425
+ }
426
+ /**
427
+ * Request to get graph data
428
+ */
429
+ interface GetGraphRequest {
430
+ /** Space/project ID to fetch graph for */
431
+ spaceId: string;
432
+ /** Pagination cursor (optional) */
433
+ cursor?: string;
434
+ /** Maximum number of nodes to return (default: 500, max: 2000) */
435
+ limit?: number;
436
+ /** Filter by node types */
437
+ nodeTypes?: NodeType[];
438
+ /** Filter by relationship types */
439
+ relationshipTypes?: EdgeType[];
440
+ /** Filter by start date (ISO 8601) */
441
+ startDate?: string;
442
+ /** Filter by end date (ISO 8601) */
443
+ endDate?: string;
444
+ }
445
+ /**
446
+ * Node details response
447
+ */
448
+ interface NodeDetails {
449
+ /** The node */
450
+ node: GraphNode;
451
+ /** Edges connected to this node */
452
+ edges: GraphEdge[];
453
+ /** Neighboring nodes */
454
+ connectedNodes: GraphNode[];
455
+ }
456
+ /**
457
+ * Request to get node details
458
+ */
459
+ interface GetNodeDetailsRequest {
460
+ /** Node ID */
461
+ nodeId: string;
462
+ }
463
+ /**
464
+ * Request to get node edges
465
+ */
466
+ interface GetNodeEdgesRequest {
467
+ /** Node ID */
468
+ nodeId: string;
469
+ /** Filter by edge types (optional) */
470
+ edgeTypes?: EdgeType[];
471
+ }
472
+ /**
473
+ * Response for get node edges
474
+ */
475
+ interface GetNodeEdgesResponse {
476
+ /** Edges connected to the node */
477
+ edges: GraphEdge[];
478
+ /** Nodes connected via these edges */
479
+ connectedNodes: GraphNode[];
480
+ }
311
481
 
312
482
  /**
313
483
  * Configuration for the HTTP client
@@ -489,4 +659,113 @@ declare class RouterResource {
489
659
  stream(request: RouterRequest): AsyncIterable<StreamChunk>;
490
660
  }
491
661
 
492
- export { APIError, AuthenticationError, type Choice, type ClientConfig$1 as ClientConfig, type CreateMemoryRequest, type IngestFileRequest, IngestResource, type IngestResponse, type IngestTextRequest, type ListMemoriesRequest, MemoriesResource, type Memory, MemoryLayerClient, MemoryLayerError, type Message, NetworkError, RateLimitError, type RouterRequest, RouterResource, type RouterResponse, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type StreamChoice, type StreamChunk, type StreamDelta, type UpdateMemoryRequest, type Usage, ValidationError, type ValidationErrorDetail };
662
+ /**
663
+ * Resource for graph visualization operations
664
+ *
665
+ * Provides methods to fetch graph data (nodes and edges) for visualization.
666
+ *
667
+ * Requirements: 6.1, 6.2, 6.3, 6.4
668
+ */
669
+ declare class GraphResource {
670
+ private httpClient;
671
+ constructor(httpClient: HTTPClient);
672
+ /**
673
+ * Get graph data for a space/project
674
+ *
675
+ * Fetches nodes (memories, documents, entities) and edges (relationships)
676
+ * for visualization. Supports pagination and filtering.
677
+ *
678
+ * @param request - Graph data request with filters
679
+ * @returns Graph data with nodes, edges, metadata, and pagination
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * const graphData = await client.graph.getGraph({
684
+ * spaceId: 'project-123',
685
+ * limit: 100,
686
+ * nodeTypes: ['memory', 'document'],
687
+ * relationshipTypes: ['extends', 'updates']
688
+ * });
689
+ *
690
+ * console.log(`Found ${graphData.nodes.length} nodes`);
691
+ * console.log(`Found ${graphData.edges.length} edges`);
692
+ * ```
693
+ *
694
+ * Requirements: 6.1
695
+ */
696
+ getGraph(request: GetGraphRequest): Promise<GraphData>;
697
+ /**
698
+ * Get detailed information for a specific node
699
+ *
700
+ * Fetches node data, connected edges, and neighboring nodes.
701
+ *
702
+ * @param request - Node details request
703
+ * @returns Node details with edges and connected nodes
704
+ *
705
+ * @example
706
+ * ```typescript
707
+ * const details = await client.graph.getNodeDetails({
708
+ * nodeId: 'memory-456'
709
+ * });
710
+ *
711
+ * console.log(`Node: ${details.node.label}`);
712
+ * console.log(`Connected to ${details.connectedNodes.length} nodes`);
713
+ * ```
714
+ *
715
+ * Requirements: 6.2
716
+ */
717
+ getNodeDetails(request: GetNodeDetailsRequest): Promise<NodeDetails>;
718
+ /**
719
+ * Get edges connected to a specific node
720
+ *
721
+ * Fetches edges and connected nodes, optionally filtered by edge type.
722
+ *
723
+ * @param request - Node edges request
724
+ * @returns Edges and connected nodes
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * const edges = await client.graph.getNodeEdges({
729
+ * nodeId: 'memory-456',
730
+ * edgeTypes: ['extends', 'updates']
731
+ * });
732
+ *
733
+ * console.log(`Found ${edges.edges.length} edges`);
734
+ * ```
735
+ *
736
+ * Requirements: 6.3
737
+ */
738
+ getNodeEdges(request: GetNodeEdgesRequest): Promise<GetNodeEdgesResponse>;
739
+ /**
740
+ * Get all graph pages using async iteration
741
+ *
742
+ * Automatically handles pagination to fetch all nodes and edges.
743
+ * Yields each page of results as they are fetched.
744
+ *
745
+ * @param request - Initial graph request (without cursor)
746
+ * @yields Graph data for each page
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
751
+ * console.log(`Page has ${page.nodes.length} nodes`);
752
+ * // Process nodes...
753
+ * }
754
+ * ```
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * // Collect all nodes
759
+ * const allNodes: GraphNode[] = [];
760
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
761
+ * allNodes.push(...page.nodes);
762
+ * }
763
+ * console.log(`Total nodes: ${allNodes.length}`);
764
+ * ```
765
+ *
766
+ * Requirements: 6.4
767
+ */
768
+ getAllGraphPages(request: Omit<GetGraphRequest, 'cursor'>): AsyncGenerator<GraphData, void, undefined>;
769
+ }
770
+
771
+ export { APIError, AuthenticationError, type Choice, type ClientConfig$1 as ClientConfig, type CreateMemoryRequest, type EdgeType, type GetGraphRequest, type GetNodeDetailsRequest, type GetNodeEdgesRequest, type GetNodeEdgesResponse, type GraphData, type GraphEdge, type GraphMetadata, type GraphNode, GraphResource, type IngestFileRequest, IngestResource, type IngestResponse, type IngestTextRequest, type ListMemoriesRequest, MemoriesResource, type Memory, MemoryLayerClient, MemoryLayerError, type MemoryStatus, type Message, NetworkError, type NodeDetails, type NodeType, type PaginationInfo, RateLimitError, type RouterRequest, RouterResource, type RouterResponse, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type StreamChoice, type StreamChunk, type StreamDelta, type UpdateMemoryRequest, type Usage, ValidationError, type ValidationErrorDetail };
package/dist/index.d.ts CHANGED
@@ -31,6 +31,7 @@ declare class MemoryLayerClient {
31
31
  private _search?;
32
32
  private _ingest?;
33
33
  private _router?;
34
+ private _graph?;
34
35
  constructor(config?: ClientConfig$1);
35
36
  /**
36
37
  * Access memory operations
@@ -48,6 +49,10 @@ declare class MemoryLayerClient {
48
49
  * Access router operations
49
50
  */
50
51
  get router(): any;
52
+ /**
53
+ * Access graph visualization operations
54
+ */
55
+ get graph(): any;
51
56
  }
52
57
 
53
58
  /**
@@ -308,6 +313,171 @@ interface StreamChunk {
308
313
  /** Array of streaming choices */
309
314
  choices: StreamChoice[];
310
315
  }
316
+ /**
317
+ * Memory status for visualization
318
+ */
319
+ type MemoryStatus = 'latest' | 'older' | 'forgotten' | 'expiring' | 'new';
320
+ /**
321
+ * Node types in the graph
322
+ */
323
+ type NodeType = 'memory' | 'document' | 'entity';
324
+ /**
325
+ * Edge types in the graph
326
+ */
327
+ type EdgeType = 'updates' | 'extends' | 'derives' | 'similarity';
328
+ /**
329
+ * Node in the graph (memory, document, or entity)
330
+ */
331
+ interface GraphNode {
332
+ /** Unique identifier for the node */
333
+ id: string;
334
+ /** Type of node */
335
+ type: NodeType;
336
+ /** Display label (truncated content or title) */
337
+ label: string;
338
+ /** Node data */
339
+ data: {
340
+ /** Full content (for memory nodes) */
341
+ content?: string;
342
+ /** Title (for document nodes) */
343
+ title?: string;
344
+ /** Memory status */
345
+ status?: MemoryStatus;
346
+ /** Creation timestamp (ISO 8601) */
347
+ createdAt: string;
348
+ /** Expiration timestamp (ISO 8601) */
349
+ expiresAt?: string;
350
+ /** Source reference */
351
+ source?: string;
352
+ /** Additional metadata */
353
+ metadata?: Record<string, any>;
354
+ };
355
+ /** Optional position hints for layout */
356
+ position?: {
357
+ x: number;
358
+ y: number;
359
+ };
360
+ }
361
+ /**
362
+ * Edge in the graph (relationship or similarity)
363
+ */
364
+ interface GraphEdge {
365
+ /** Unique identifier for the edge */
366
+ id: string;
367
+ /** Source node ID */
368
+ source: string;
369
+ /** Target node ID */
370
+ target: string;
371
+ /** Type of edge */
372
+ type: EdgeType;
373
+ /** Display label for the edge */
374
+ label?: string;
375
+ /** Edge data */
376
+ data: {
377
+ /** Strength of the relationship (0.0 to 1.0) */
378
+ strength: number;
379
+ /** Additional metadata */
380
+ metadata?: Record<string, any>;
381
+ };
382
+ }
383
+ /**
384
+ * Graph metadata and statistics
385
+ */
386
+ interface GraphMetadata {
387
+ /** Total number of nodes */
388
+ totalNodes: number;
389
+ /** Number of memory nodes */
390
+ memoryCount: number;
391
+ /** Number of document nodes */
392
+ documentCount: number;
393
+ /** Number of entity nodes */
394
+ entityCount: number;
395
+ /** Total number of edges */
396
+ totalEdges: number;
397
+ /** Number of relationship edges */
398
+ relationshipCount: number;
399
+ /** Number of similarity edges */
400
+ similarityCount: number;
401
+ }
402
+ /**
403
+ * Pagination information
404
+ */
405
+ interface PaginationInfo {
406
+ /** Whether there are more results */
407
+ hasMore: boolean;
408
+ /** Cursor for the next page */
409
+ nextCursor?: string;
410
+ /** Total count (optional, may be expensive to compute) */
411
+ totalCount?: number;
412
+ }
413
+ /**
414
+ * Complete graph data structure
415
+ */
416
+ interface GraphData {
417
+ /** Array of nodes */
418
+ nodes: GraphNode[];
419
+ /** Array of edges */
420
+ edges: GraphEdge[];
421
+ /** Graph metadata and statistics */
422
+ metadata: GraphMetadata;
423
+ /** Pagination information */
424
+ pagination: PaginationInfo;
425
+ }
426
+ /**
427
+ * Request to get graph data
428
+ */
429
+ interface GetGraphRequest {
430
+ /** Space/project ID to fetch graph for */
431
+ spaceId: string;
432
+ /** Pagination cursor (optional) */
433
+ cursor?: string;
434
+ /** Maximum number of nodes to return (default: 500, max: 2000) */
435
+ limit?: number;
436
+ /** Filter by node types */
437
+ nodeTypes?: NodeType[];
438
+ /** Filter by relationship types */
439
+ relationshipTypes?: EdgeType[];
440
+ /** Filter by start date (ISO 8601) */
441
+ startDate?: string;
442
+ /** Filter by end date (ISO 8601) */
443
+ endDate?: string;
444
+ }
445
+ /**
446
+ * Node details response
447
+ */
448
+ interface NodeDetails {
449
+ /** The node */
450
+ node: GraphNode;
451
+ /** Edges connected to this node */
452
+ edges: GraphEdge[];
453
+ /** Neighboring nodes */
454
+ connectedNodes: GraphNode[];
455
+ }
456
+ /**
457
+ * Request to get node details
458
+ */
459
+ interface GetNodeDetailsRequest {
460
+ /** Node ID */
461
+ nodeId: string;
462
+ }
463
+ /**
464
+ * Request to get node edges
465
+ */
466
+ interface GetNodeEdgesRequest {
467
+ /** Node ID */
468
+ nodeId: string;
469
+ /** Filter by edge types (optional) */
470
+ edgeTypes?: EdgeType[];
471
+ }
472
+ /**
473
+ * Response for get node edges
474
+ */
475
+ interface GetNodeEdgesResponse {
476
+ /** Edges connected to the node */
477
+ edges: GraphEdge[];
478
+ /** Nodes connected via these edges */
479
+ connectedNodes: GraphNode[];
480
+ }
311
481
 
312
482
  /**
313
483
  * Configuration for the HTTP client
@@ -489,4 +659,113 @@ declare class RouterResource {
489
659
  stream(request: RouterRequest): AsyncIterable<StreamChunk>;
490
660
  }
491
661
 
492
- export { APIError, AuthenticationError, type Choice, type ClientConfig$1 as ClientConfig, type CreateMemoryRequest, type IngestFileRequest, IngestResource, type IngestResponse, type IngestTextRequest, type ListMemoriesRequest, MemoriesResource, type Memory, MemoryLayerClient, MemoryLayerError, type Message, NetworkError, RateLimitError, type RouterRequest, RouterResource, type RouterResponse, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type StreamChoice, type StreamChunk, type StreamDelta, type UpdateMemoryRequest, type Usage, ValidationError, type ValidationErrorDetail };
662
+ /**
663
+ * Resource for graph visualization operations
664
+ *
665
+ * Provides methods to fetch graph data (nodes and edges) for visualization.
666
+ *
667
+ * Requirements: 6.1, 6.2, 6.3, 6.4
668
+ */
669
+ declare class GraphResource {
670
+ private httpClient;
671
+ constructor(httpClient: HTTPClient);
672
+ /**
673
+ * Get graph data for a space/project
674
+ *
675
+ * Fetches nodes (memories, documents, entities) and edges (relationships)
676
+ * for visualization. Supports pagination and filtering.
677
+ *
678
+ * @param request - Graph data request with filters
679
+ * @returns Graph data with nodes, edges, metadata, and pagination
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * const graphData = await client.graph.getGraph({
684
+ * spaceId: 'project-123',
685
+ * limit: 100,
686
+ * nodeTypes: ['memory', 'document'],
687
+ * relationshipTypes: ['extends', 'updates']
688
+ * });
689
+ *
690
+ * console.log(`Found ${graphData.nodes.length} nodes`);
691
+ * console.log(`Found ${graphData.edges.length} edges`);
692
+ * ```
693
+ *
694
+ * Requirements: 6.1
695
+ */
696
+ getGraph(request: GetGraphRequest): Promise<GraphData>;
697
+ /**
698
+ * Get detailed information for a specific node
699
+ *
700
+ * Fetches node data, connected edges, and neighboring nodes.
701
+ *
702
+ * @param request - Node details request
703
+ * @returns Node details with edges and connected nodes
704
+ *
705
+ * @example
706
+ * ```typescript
707
+ * const details = await client.graph.getNodeDetails({
708
+ * nodeId: 'memory-456'
709
+ * });
710
+ *
711
+ * console.log(`Node: ${details.node.label}`);
712
+ * console.log(`Connected to ${details.connectedNodes.length} nodes`);
713
+ * ```
714
+ *
715
+ * Requirements: 6.2
716
+ */
717
+ getNodeDetails(request: GetNodeDetailsRequest): Promise<NodeDetails>;
718
+ /**
719
+ * Get edges connected to a specific node
720
+ *
721
+ * Fetches edges and connected nodes, optionally filtered by edge type.
722
+ *
723
+ * @param request - Node edges request
724
+ * @returns Edges and connected nodes
725
+ *
726
+ * @example
727
+ * ```typescript
728
+ * const edges = await client.graph.getNodeEdges({
729
+ * nodeId: 'memory-456',
730
+ * edgeTypes: ['extends', 'updates']
731
+ * });
732
+ *
733
+ * console.log(`Found ${edges.edges.length} edges`);
734
+ * ```
735
+ *
736
+ * Requirements: 6.3
737
+ */
738
+ getNodeEdges(request: GetNodeEdgesRequest): Promise<GetNodeEdgesResponse>;
739
+ /**
740
+ * Get all graph pages using async iteration
741
+ *
742
+ * Automatically handles pagination to fetch all nodes and edges.
743
+ * Yields each page of results as they are fetched.
744
+ *
745
+ * @param request - Initial graph request (without cursor)
746
+ * @yields Graph data for each page
747
+ *
748
+ * @example
749
+ * ```typescript
750
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
751
+ * console.log(`Page has ${page.nodes.length} nodes`);
752
+ * // Process nodes...
753
+ * }
754
+ * ```
755
+ *
756
+ * @example
757
+ * ```typescript
758
+ * // Collect all nodes
759
+ * const allNodes: GraphNode[] = [];
760
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
761
+ * allNodes.push(...page.nodes);
762
+ * }
763
+ * console.log(`Total nodes: ${allNodes.length}`);
764
+ * ```
765
+ *
766
+ * Requirements: 6.4
767
+ */
768
+ getAllGraphPages(request: Omit<GetGraphRequest, 'cursor'>): AsyncGenerator<GraphData, void, undefined>;
769
+ }
770
+
771
+ export { APIError, AuthenticationError, type Choice, type ClientConfig$1 as ClientConfig, type CreateMemoryRequest, type EdgeType, type GetGraphRequest, type GetNodeDetailsRequest, type GetNodeEdgesRequest, type GetNodeEdgesResponse, type GraphData, type GraphEdge, type GraphMetadata, type GraphNode, GraphResource, type IngestFileRequest, IngestResource, type IngestResponse, type IngestTextRequest, type ListMemoriesRequest, MemoriesResource, type Memory, MemoryLayerClient, MemoryLayerError, type MemoryStatus, type Message, NetworkError, type NodeDetails, type NodeType, type PaginationInfo, RateLimitError, type RouterRequest, RouterResource, type RouterResponse, type SearchRequest, SearchResource, type SearchResponse, type SearchResult, type StreamChoice, type StreamChunk, type StreamDelta, type UpdateMemoryRequest, type Usage, ValidationError, type ValidationErrorDetail };
package/dist/index.js CHANGED
@@ -413,6 +413,191 @@ var init_router = __esm({
413
413
  }
414
414
  });
415
415
 
416
+ // src/resources/graph.ts
417
+ var graph_exports = {};
418
+ __export(graph_exports, {
419
+ GraphResource: () => GraphResource
420
+ });
421
+ var GraphResource;
422
+ var init_graph = __esm({
423
+ "src/resources/graph.ts"() {
424
+ "use strict";
425
+ init_errors();
426
+ GraphResource = class {
427
+ constructor(httpClient) {
428
+ this.httpClient = httpClient;
429
+ }
430
+ /**
431
+ * Get graph data for a space/project
432
+ *
433
+ * Fetches nodes (memories, documents, entities) and edges (relationships)
434
+ * for visualization. Supports pagination and filtering.
435
+ *
436
+ * @param request - Graph data request with filters
437
+ * @returns Graph data with nodes, edges, metadata, and pagination
438
+ *
439
+ * @example
440
+ * ```typescript
441
+ * const graphData = await client.graph.getGraph({
442
+ * spaceId: 'project-123',
443
+ * limit: 100,
444
+ * nodeTypes: ['memory', 'document'],
445
+ * relationshipTypes: ['extends', 'updates']
446
+ * });
447
+ *
448
+ * console.log(`Found ${graphData.nodes.length} nodes`);
449
+ * console.log(`Found ${graphData.edges.length} edges`);
450
+ * ```
451
+ *
452
+ * Requirements: 6.1
453
+ */
454
+ async getGraph(request) {
455
+ if (!request.spaceId || request.spaceId.trim().length === 0) {
456
+ throw new ValidationError(
457
+ "Space ID is required",
458
+ [{ field: "spaceId", message: "Space ID is required" }]
459
+ );
460
+ }
461
+ const query = {};
462
+ if (request.cursor) {
463
+ query.cursor = request.cursor;
464
+ }
465
+ if (request.limit !== void 0) {
466
+ query.limit = request.limit.toString();
467
+ }
468
+ if (request.nodeTypes && request.nodeTypes.length > 0) {
469
+ query.nodeTypes = request.nodeTypes.join(",");
470
+ }
471
+ if (request.relationshipTypes && request.relationshipTypes.length > 0) {
472
+ query.relationshipTypes = request.relationshipTypes.join(",");
473
+ }
474
+ if (request.startDate) {
475
+ query.startDate = request.startDate;
476
+ }
477
+ if (request.endDate) {
478
+ query.endDate = request.endDate;
479
+ }
480
+ return this.httpClient.request({
481
+ method: "GET",
482
+ path: `/v1/graph/spaces/${request.spaceId}`,
483
+ query
484
+ });
485
+ }
486
+ /**
487
+ * Get detailed information for a specific node
488
+ *
489
+ * Fetches node data, connected edges, and neighboring nodes.
490
+ *
491
+ * @param request - Node details request
492
+ * @returns Node details with edges and connected nodes
493
+ *
494
+ * @example
495
+ * ```typescript
496
+ * const details = await client.graph.getNodeDetails({
497
+ * nodeId: 'memory-456'
498
+ * });
499
+ *
500
+ * console.log(`Node: ${details.node.label}`);
501
+ * console.log(`Connected to ${details.connectedNodes.length} nodes`);
502
+ * ```
503
+ *
504
+ * Requirements: 6.2
505
+ */
506
+ async getNodeDetails(request) {
507
+ if (!request.nodeId || request.nodeId.trim().length === 0) {
508
+ throw new ValidationError(
509
+ "Node ID is required",
510
+ [{ field: "nodeId", message: "Node ID is required" }]
511
+ );
512
+ }
513
+ return this.httpClient.request({
514
+ method: "GET",
515
+ path: `/v1/graph/nodes/${request.nodeId}`
516
+ });
517
+ }
518
+ /**
519
+ * Get edges connected to a specific node
520
+ *
521
+ * Fetches edges and connected nodes, optionally filtered by edge type.
522
+ *
523
+ * @param request - Node edges request
524
+ * @returns Edges and connected nodes
525
+ *
526
+ * @example
527
+ * ```typescript
528
+ * const edges = await client.graph.getNodeEdges({
529
+ * nodeId: 'memory-456',
530
+ * edgeTypes: ['extends', 'updates']
531
+ * });
532
+ *
533
+ * console.log(`Found ${edges.edges.length} edges`);
534
+ * ```
535
+ *
536
+ * Requirements: 6.3
537
+ */
538
+ async getNodeEdges(request) {
539
+ if (!request.nodeId || request.nodeId.trim().length === 0) {
540
+ throw new ValidationError(
541
+ "Node ID is required",
542
+ [{ field: "nodeId", message: "Node ID is required" }]
543
+ );
544
+ }
545
+ const query = {};
546
+ if (request.edgeTypes && request.edgeTypes.length > 0) {
547
+ query.edgeTypes = request.edgeTypes.join(",");
548
+ }
549
+ return this.httpClient.request({
550
+ method: "GET",
551
+ path: `/v1/graph/nodes/${request.nodeId}/edges`,
552
+ query
553
+ });
554
+ }
555
+ /**
556
+ * Get all graph pages using async iteration
557
+ *
558
+ * Automatically handles pagination to fetch all nodes and edges.
559
+ * Yields each page of results as they are fetched.
560
+ *
561
+ * @param request - Initial graph request (without cursor)
562
+ * @yields Graph data for each page
563
+ *
564
+ * @example
565
+ * ```typescript
566
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
567
+ * console.log(`Page has ${page.nodes.length} nodes`);
568
+ * // Process nodes...
569
+ * }
570
+ * ```
571
+ *
572
+ * @example
573
+ * ```typescript
574
+ * // Collect all nodes
575
+ * const allNodes: GraphNode[] = [];
576
+ * for await (const page of client.graph.getAllGraphPages({ spaceId: 'project-123' })) {
577
+ * allNodes.push(...page.nodes);
578
+ * }
579
+ * console.log(`Total nodes: ${allNodes.length}`);
580
+ * ```
581
+ *
582
+ * Requirements: 6.4
583
+ */
584
+ async *getAllGraphPages(request) {
585
+ let cursor;
586
+ let hasMore = true;
587
+ while (hasMore) {
588
+ const page = await this.getGraph({
589
+ ...request,
590
+ cursor
591
+ });
592
+ yield page;
593
+ cursor = page.pagination.nextCursor;
594
+ hasMore = page.pagination.hasMore;
595
+ }
596
+ }
597
+ };
598
+ }
599
+ });
600
+
416
601
  // src/http-client.ts
417
602
  init_errors();
418
603
  var HTTPClient = class {
@@ -686,6 +871,16 @@ var MemoryLayerClient = class {
686
871
  }
687
872
  return this._router;
688
873
  }
874
+ /**
875
+ * Access graph visualization operations
876
+ */
877
+ get graph() {
878
+ if (!this._graph) {
879
+ const { GraphResource: GraphResource2 } = (init_graph(), __toCommonJS(graph_exports));
880
+ this._graph = new GraphResource2(this.httpClient);
881
+ }
882
+ return this._graph;
883
+ }
689
884
  };
690
885
 
691
886
  // src/index.ts
@@ -694,9 +889,11 @@ init_memories();
694
889
  init_search();
695
890
  init_ingest();
696
891
  init_router();
892
+ init_graph();
697
893
  export {
698
894
  APIError,
699
895
  AuthenticationError,
896
+ GraphResource,
700
897
  IngestResource,
701
898
  MemoriesResource,
702
899
  MemoryLayerClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memorylayerai/sdk",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "description": "Official Node.js/TypeScript SDK for MemoryLayer",
6
6
  "main": "dist/index.js",