From 3ed1a9d3399b188ab03b54380455d9581327a245 Mon Sep 17 00:00:00 2001 From: Shanu Date: Fri, 20 Mar 2026 16:59:02 +0530 Subject: [PATCH] Add new api endpoints in sdk - Updated README.md to include additional API functionalities: chat, thoughts, and interactions. - Expanded .gitignore to cover more file types and directories, including Python and Rust artifacts, improving project cleanliness. - Added new interfaces and methods in src/index.ts for chat and sync functionalities, enhancing SDK capabilities. - Introduced tests for the new chatMemory and listDocuments methods to ensure proper functionality. --- packages/sdk-typescript/.gitignore | 56 ++- packages/sdk-typescript/README.md | 152 ++++++- packages/sdk-typescript/src/index.ts | 424 +++++++++++++++++--- packages/sdk-typescript/test/client.test.ts | 34 ++ 4 files changed, 597 insertions(+), 69 deletions(-) diff --git a/packages/sdk-typescript/.gitignore b/packages/sdk-typescript/.gitignore index 1aba534..113c6b1 100644 --- a/packages/sdk-typescript/.gitignore +++ b/packages/sdk-typescript/.gitignore @@ -1,24 +1,44 @@ -# Node -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# Build output -dist/ -*.tsbuildinfo -*.js.map +# OS / Editor +.DS_Store +.vscode/ +.idea/ +*.swp +*.swo -# Environment +# Environment files .env .env.* +!.env.example -# Testing +# Python +.venv/ +venv/ +__pycache__/ +*.py[cod] +*.egg-info/ +.eggs/ +.pytest_cache/ +.coverage coverage/ +dist/ +build/ -# Editors -.DS_Store -.idea/ -.vscode/ -*.swp -*.swo +# Node / TypeScript +node_modules/ +dist/ +build/ +*.tsbuildinfo + +# Package manager lock/debug artifacts (matches your per-plugin style) +package-lock.json +npm-debug.log* +yarn.lock +.pnpm-debug.log* + +# Rust (if present) +target/ + +# Neocortex / plugin runtime data +corpus/ +db/ +results/ \ No newline at end of file diff --git a/packages/sdk-typescript/README.md b/packages/sdk-typescript/README.md index 8d8862d..18574fc 100644 --- a/packages/sdk-typescript/README.md +++ b/packages/sdk-typescript/README.md @@ -1,7 +1,6 @@ # @alphahuman/memory-sdk -TypeScript / JavaScript SDK for the [Alphahuman Memory API](https://alphahuman.xyz), aligned with the backend API: insert, query, admin/delete, recall, and memories/recall. - +TypeScript / JavaScript SDK for the [Alphahuman Memory API](https://alphahuman.xyz), aligned with the backend API: insert, query, chat, documents, admin/delete, recall, thoughts, interact, and more. ## Requirements - Node.js ≥ 18 (uses native `fetch`) @@ -121,6 +120,155 @@ Recall memories from Ebbinghaus bank. **POST /v1/memory/memories/recall** Returns `RecallMemoriesResponse` with `data: { memories }`. +### `client.chatMemory(params)` + +Chat with DeltaNet memory cache. **POST /v1/memory/chat** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `messages` | `ChatMessage[]` | ✓ | List of messages `[{role, content}]` | +| `temperature` | `number` | | Optional temperature | +| `maxTokens` | `number` | | Optional max completion tokens | + +Returns `ChatMemoryResponse`. + +### `client.recallThoughts(params?)` + +Generate reflective thoughts. **POST /v1/memory/memories/thoughts** + +| Field | Type | Description | +|-------|------|-------------| +| `namespace` | `string` | Optional namespace | +| `thoughtPrompt` | `string` | Optional custom LLM prompt | +| `maxChunks` | `number` | Number of chunks to recall | + +Returns `RecallThoughtsResponse`. + +### `client.syncMemory(params)` + +Sync OpenClaw memory files. **POST /v1/memory/sync** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `workspaceId` | `string` | ✓ | Workspace identifier | +| `agentId` | `string` | ✓ | Agent identifier | +| `source` | `'startup' \| 'agent_end'` | | Optional source | +| `files` | `{ filePath: string; content: string; timestamp: string; hash: string }[]` | ✓ | Files to sync | + +Returns `SyncMemoryResponse`. + +### `client.insertDocument(params)` + +Ingest a single memory document. **POST /v1/memory/documents** + +Supports the same fields as `insertMemory` (`title`, `content`, `namespace`, optional `sourceType`, `metadata`, `priority`, `createdAt`, `updatedAt`, `documentId`). + +### `client.insertDocumentsBatch(params)` + +Ingest multiple memory documents in batch. **POST /v1/memory/documents/batch** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `items` | `{ title: string; content: string; namespace: string; ... }[]` | ✓ | Document items | + +Returns `InsertDocumentsBatchResponse`. + +### `client.listDocuments(params?)` + +List ingested memory documents. **GET /v1/memory/documents** + +| Field | Type | Description | +|-------|------|-------------| +| `namespace` | `string` | Optional namespace | +| `limit` | `number` | Optional page size | +| `offset` | `number` | Optional page offset | + +Returns `ListDocumentsResponse`. + +### `client.getDocument(params)` + +Get details for a memory document. **GET /v1/memory/documents/:documentId** + +| Field | Type | Description | +|-------|------|-------------| +| `documentId` | `string` | Required | +| `namespace` | `string` | Optional namespace | + +Returns `GetDocumentResponse`. + +### `client.deleteDocument(params)` + +Delete a memory document. **DELETE /v1/memory/documents/:documentId** + +| Field | Type | Description | +|-------|------|-------------| +| `documentId` | `string` | Required | +| `namespace` | `string` | Required | + +Returns `DeleteMemoryResponse`. + +### `client.queryMemoryContext(params)` + +Query memory context. **POST /v1/memory/queries** + +| Field | Type | Description | +|-------|------|-------------| +| `query` | `string` | ✓ Query string | +| `includeReferences` | `boolean` | Include references in response | +| `namespace` | `string` | Optional namespace | +| `maxChunks` | `number` | Optional chunk limit | +| `documentIds` | `string[]` | Optional document filters | +| `recallOnly` | `boolean` | Recall-only mode | +| `llmQuery` | `string` | Optional LLM query override | + +Returns `QueryMemoryResponse`. + +### `client.chatMemoryContext(params)` + +Chat with memory context. **POST /v1/memory/conversations** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `messages` | `[{ role: string; content: string }]` | ✓ | Conversation messages | +| `temperature` | `number` | | Optional temperature | +| `maxTokens` | `number` | | Optional token limit | + +Returns `ChatMemoryResponse`. + +### `client.recordInteractions(params)` + +Record interaction signals. **POST /v1/memory/interactions** + +| Field | Type | Required | Description | +|-------|------|----------|-------------| +| `namespace` | `string` | ✓ | Namespace | +| `entityNames` | `string[]` | ✓ | Entity names | +| `description` | `string` | | Optional description | +| `interactionLevel` | `'view' \| 'read' \| 'react' \| 'engage' \| 'create'` | | Optional interaction level | +| `interactionLevels` | same union array | | Optional multiple interaction levels | + +Returns `InteractMemoryResponse`. + +### `client.getIngestionJob(jobId)` + +Get memory ingestion job status. **GET /v1/memory/ingestion/jobs/:jobId** + +Returns `GetIngestionJobResponse`. + +### `client.getGraphSnapshot(params?)` + +Get admin graph snapshot. **GET /v1/memory/admin/graph-snapshot** + +| Field | Type | Description | +|-------|------|-------------| +| `namespace` | `string` | Optional namespace | +| `mode` | `'master' \| 'latest_chunks'` | Optional graph mode | +| `limit` | `number` | Optional limit | +| `seed_limit` | `number` | Optional seed limit | + +Returns `GetGraphSnapshotResponse`. + + ## Error handling All API errors throw `AlphahumanError` (extends `Error`) with `status` (HTTP status code) and `body` (parsed response when available). diff --git a/packages/sdk-typescript/src/index.ts b/packages/sdk-typescript/src/index.ts index de2edb8..be203b2 100644 --- a/packages/sdk-typescript/src/index.ts +++ b/packages/sdk-typescript/src/index.ts @@ -1,5 +1,5 @@ // Alphahuman Memory SDK for TypeScript -// Aligned with AlphaHuman backend API: insert, query, admin/delete, recall, memories/recall. +// Aligned with AlphaHuman backend API: insert, query, admin/delete, recall, memories/recall, chat, thought, interact, etc. const DEFAULT_BASE_URL = 'https://staging-api.alphahuman.xyz'; @@ -43,17 +43,216 @@ export interface InsertMemoryParams { export interface InsertMemoryResponse { success: boolean; data: { - status: string; - stats: Record; + status?: string; + stats?: Record; usage?: { llm_input_tokens: number; llm_output_tokens: number; embedding_tokens: number; cost_usd: number; }; + jobId?: string; + state?: string; }; } +// ---------- Sync ---------- + +export interface SyncFileParams { + filePath: string; + content: string; + timestamp: string; + hash: string; +} + +export interface SyncMemoryParams { + workspaceId: string; + agentId: string; + source?: 'startup' | 'agent_end'; + files: SyncFileParams[]; +} + +export interface SyncMemoryResponse { + success: boolean; + data: { + synced: number; + jobId?: string; + state?: string; + }; +} + +// ---------- Chat ---------- + +export interface ChatMessage { + role: string; + content: string; +} + +export interface ChatMemoryParams { + messages: ChatMessage[]; + temperature?: number; + maxTokens?: number; + max_tokens?: number; +} + +export interface ChatMemoryResponse { + success: boolean; + data: { + content?: string; + usage?: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + }; + model?: string; + // For pending background requests via api key + jobId?: string; + state?: string; + }; +} + +// ---------- Interact ---------- + +export interface InteractMemoryParams { + namespace: string; + entityNames: string[]; + description?: string; + interactionLevel?: 'view' | 'read' | 'react' | 'engage' | 'create'; + interactionLevels?: Array<'view' | 'read' | 'react' | 'engage' | 'create'>; + timestamp?: number; +} + +export interface InteractMemoryResponse { + success: boolean; + data: { + status?: string; + interactionsRecorded?: number; + entityNames?: string[]; + timestampUsed?: number; + jobId?: string; + state?: string; + }; +} + +// ---------- Recall Thoughts ---------- + +export interface RecallThoughtsParams { + namespace?: string; + maxChunks?: number; + max_chunks?: number; + temperature?: number; + randomnessSeed?: number; + randomness_seed?: number; + persist?: boolean; + enablePredictionCheck?: boolean; + enable_prediction_check?: boolean; + thoughtPrompt?: string; + thought_prompt?: string; +} + +export interface RecallThoughtsResponse { + success: boolean; + data: { + thought?: string; + context?: Record; + llm_context_message?: string; + usage?: { + llm_input_tokens: number; + llm_output_tokens: number; + embedding_tokens: number; + cost_usd: number; + }; + cached?: boolean; + latency_seconds?: number; + persisted?: boolean; + jobId?: string; + state?: string; + }; +} + +// ---------- Ingestion Jobs ---------- + +export interface GetIngestionJobResponse { + success: boolean; + data: { + jobId: string; + state: string; + endpoint: string; + attempts: number; + error: string | null; + response: Record | null; + createdAt: string; + startedAt: string | null; + completedAt: string | null; + }; +} + +// ---------- Documents ---------- + +export interface InsertDocumentsBatchParams { + items: Array<{ + title: string; + content: string; + namespace: string; + sourceType?: 'doc' | 'chat' | 'email'; + metadata?: Record; + priority?: 'high' | 'medium' | 'low'; + createdAt?: number; + updatedAt?: number; + documentId?: string; + }>; +} + +export interface InsertDocumentsBatchResponse { + success: boolean; + data: { + status?: string; + results?: any[]; + state?: string; + accepted?: Array<{ index: number; jobId: string }>; + }; +} + +export interface ListDocumentsParams { + namespace?: string; + limit?: number; + offset?: number; +} + +export interface ListDocumentsResponse { + success: boolean; + data: Record; +} + +export interface GetDocumentParams { + documentId: string; + namespace?: string; +} + +export interface GetDocumentResponse { + success: boolean; + data: Record; +} + +export interface DeleteDocumentParams { + documentId: string; + namespace: string; +} + +// ---------- Graph Snapshot ---------- + +export interface GetGraphSnapshotParams { + namespace?: string; + mode?: 'master' | 'latest_chunks'; + limit?: number; + seed_limit?: number; +} + +export interface GetGraphSnapshotResponse { + success: boolean; + data: Record; +} + // ---------- Query ---------- export interface QueryMemoryParams { @@ -63,6 +262,7 @@ export interface QueryMemoryParams { namespace?: string; maxChunks?: number; documentIds?: string[]; + recallOnly?: boolean; llmQuery?: string; } @@ -82,9 +282,11 @@ export interface QueryMemoryResponse { embedding_tokens: number; cost_usd: number; }; - cached: boolean; + cached?: boolean; llmContextMessage?: string; response?: string; + jobId?: string; + state?: string; }; } @@ -98,11 +300,13 @@ export interface DeleteMemoryParams { export interface DeleteMemoryResponse { success: boolean; data: { - status: string; - userId: string; + status?: string; + userId?: string; namespace?: string; - nodesDeleted: number; - message: string; + nodesDeleted?: number; + message?: string; + jobId?: string; + state?: string; }; } @@ -123,7 +327,7 @@ export interface RecallMemoryResponse { embedding_tokens: number; cost_usd: number; }; - cached: boolean; + cached?: boolean; llmContextMessage?: string; response?: string; latencySeconds?: number; @@ -132,6 +336,8 @@ export interface RecallMemoryResponse { numRelations: number; numChunks: number; }; + jobId?: string; + state?: string; }; } @@ -158,7 +364,9 @@ export interface MemoryItemRecalled { export interface RecallMemoriesResponse { success: boolean; data: { - memories: MemoryItemRecalled[]; + memories?: MemoryItemRecalled[]; + jobId?: string; + state?: string; }; } @@ -194,51 +402,32 @@ export class AlphahumanMemoryClient { this.token = config.token; } + // --- Core / Legacy Endpoints --- + /** Insert (ingest) a document into memory. POST /v1/memory/insert */ async insertMemory(params: InsertMemoryParams): Promise { - if (!params.title || typeof params.title !== 'string') { - throw new Error('title is required and must be a string'); - } - if (!params.content || typeof params.content !== 'string') { - throw new Error('content is required and must be a string'); - } - if (!params.namespace || typeof params.namespace !== 'string') { - throw new Error('namespace is required and must be a string'); - } - const body = { - title: params.title, - content: params.content, - namespace: params.namespace, - sourceType: params.sourceType ?? 'doc', - metadata: params.metadata, - priority: params.priority, - createdAt: params.createdAt, - updatedAt: params.updatedAt, - documentId: params.documentId, - }; - return this.post('/v1/memory/insert', body); + this.validateInsertParams(params); + return this.post('/v1/memory/insert', params); + } + + /** Sync OpenClaw memory files. POST /v1/memory/sync */ + async syncMemory(params: SyncMemoryParams): Promise { + if (!params.workspaceId) throw new Error('workspaceId is required'); + if (!params.agentId) throw new Error('agentId is required'); + if (!params.files || !Array.isArray(params.files)) throw new Error('files array is required'); + return this.post('/v1/memory/sync', params); } /** Query memory via RAG. POST /v1/memory/query */ async queryMemory(params: QueryMemoryParams): Promise { - if (!params.query || typeof params.query !== 'string') { - throw new Error('query is required and must be a string'); - } - if ( - params.maxChunks !== undefined && - (typeof params.maxChunks !== 'number' || params.maxChunks < 1 || params.maxChunks > 200) - ) { - throw new Error('maxChunks must be between 1 and 200'); - } - const body = { - query: params.query, - includeReferences: params.includeReferences, - namespace: params.namespace, - maxChunks: params.maxChunks, - documentIds: params.documentIds, - llmQuery: params.llmQuery, - }; - return this.post('/v1/memory/query', body); + this.validateQueryParams(params); + return this.post('/v1/memory/query', params); + } + + /** Chat with DeltaNet memory cache. POST /v1/memory/chat */ + async chatMemory(params: ChatMemoryParams): Promise { + if (!params.messages || !Array.isArray(params.messages)) throw new Error('messages array is required'); + return this.post('/v1/memory/chat', params); } /** Delete memory (admin). POST /v1/memory/admin/delete */ @@ -248,6 +437,13 @@ export class AlphahumanMemoryClient { }); } + /** Record entity interactions. POST /v1/memory/interact */ + async interactMemory(params: InteractMemoryParams): Promise { + if (!params.namespace) throw new Error('namespace is required'); + if (!params.entityNames || !Array.isArray(params.entityNames)) throw new Error('entityNames array is required'); + return this.post('/v1/memory/interact', params); + } + /** Recall context from Master node. POST /v1/memory/recall */ async recallMemory(params: RecallMemoryParams = {}): Promise { if ( @@ -284,6 +480,125 @@ export class AlphahumanMemoryClient { }); } + /** Generate reflective thoughts. POST /v1/memory/memories/thoughts */ + async recallThoughts(params: RecallThoughtsParams = {}): Promise { + return this.post('/v1/memory/memories/thoughts', params); + } + + /** Get memory ingestion job status. GET /v1/memory/ingestion/jobs/:jobId */ + async getIngestionJob(jobId: string): Promise { + if (!jobId) throw new Error('jobId is required'); + return this.get(`/v1/memory/ingestion/jobs/${encodeURIComponent(jobId)}`); + } + + // --- Document & Mirrored Endpoints --- + + /** Ingest a single memory document. POST /v1/memory/documents */ + async insertDocument(params: InsertMemoryParams): Promise { + this.validateInsertParams(params); + return this.post('/v1/memory/documents', params); + } + + /** Ingest multiple memory documents in batch. POST /v1/memory/documents/batch */ + async insertDocumentsBatch(params: InsertDocumentsBatchParams): Promise { + if (!params.items || !Array.isArray(params.items) || params.items.length === 0) { + throw new Error('items must be a non-empty array'); + } + return this.post('/v1/memory/documents/batch', params); + } + + /** List ingested memory documents. GET /v1/memory/documents */ + async listDocuments(params: ListDocumentsParams = {}): Promise { + const search = new URLSearchParams(); + if (params.namespace) search.append('namespace', params.namespace); + if (params.limit !== undefined) search.append('limit', String(params.limit)); + if (params.offset !== undefined) search.append('offset', String(params.offset)); + const qs = search.toString() ? `?${search.toString()}` : ''; + return this.get(`/v1/memory/documents${qs}`); + } + + /** Get details for a memory document. GET /v1/memory/documents/:documentId */ + async getDocument(params: GetDocumentParams): Promise { + if (!params.documentId) throw new Error('documentId is required'); + const qs = params.namespace ? `?namespace=${encodeURIComponent(params.namespace)}` : ''; + return this.get(`/v1/memory/documents/${encodeURIComponent(params.documentId)}${qs}`); + } + + /** Delete a memory document. DELETE /v1/memory/documents/:documentId */ + async deleteDocument(params: DeleteDocumentParams): Promise { + if (!params.documentId) throw new Error('documentId is required'); + if (!params.namespace) throw new Error('namespace is required'); + const qs = `?namespace=${encodeURIComponent(params.namespace)}`; + return this.delete(`/v1/memory/documents/${encodeURIComponent(params.documentId)}${qs}`); + } + + /** Get admin graph snapshot. GET /v1/memory/admin/graph-snapshot */ + async getGraphSnapshot(params: GetGraphSnapshotParams = {}): Promise { + const search = new URLSearchParams(); + if (params.namespace) search.append('namespace', params.namespace); + if (params.mode) search.append('mode', params.mode); + if (params.limit !== undefined) search.append('limit', String(params.limit)); + if (params.seed_limit !== undefined) search.append('seed_limit', String(params.seed_limit)); + const qs = search.toString() ? `?${search.toString()}` : ''; + return this.get(`/v1/memory/admin/graph-snapshot${qs}`); + } + + /** Query memory context. POST /v1/memory/queries */ + async queryMemoryContext(params: QueryMemoryParams): Promise { + this.validateQueryParams(params); + return this.post('/v1/memory/queries', params); + } + + /** Chat with memory context. POST /v1/memory/conversations */ + async chatMemoryContext(params: ChatMemoryParams): Promise { + if (!params.messages || !Array.isArray(params.messages)) throw new Error('messages array is required'); + return this.post('/v1/memory/conversations', params); + } + + /** Record interaction signals. POST /v1/memory/interactions */ + async recordInteractions(params: InteractMemoryParams): Promise { + if (!params.namespace) throw new Error('namespace is required'); + if (!params.entityNames || !Array.isArray(params.entityNames)) throw new Error('entityNames array is required'); + return this.post('/v1/memory/interactions', params); + } + + // --- Helpers --- + + private validateInsertParams(params: InsertMemoryParams) { + if (!params.title || typeof params.title !== 'string') { + throw new Error('title is required and must be a string'); + } + if (!params.content || typeof params.content !== 'string') { + throw new Error('content is required and must be a string'); + } + if (!params.namespace || typeof params.namespace !== 'string') { + throw new Error('namespace is required and must be a string'); + } + } + + private validateQueryParams(params: QueryMemoryParams) { + if (!params.query || typeof params.query !== 'string') { + throw new Error('query is required and must be a string'); + } + if ( + params.maxChunks !== undefined && + (typeof params.maxChunks !== 'number' || params.maxChunks < 1 || params.maxChunks > 200) + ) { + throw new Error('maxChunks must be between 1 and 200'); + } + } + + private async get(path: string): Promise { + const url = `${this.baseUrl}${path}`; + const res = await fetch(url, { + method: 'GET', + headers: { + Authorization: `Bearer ${this.token}`, + }, + }); + return this.handleResponse(res); + } + private async post(path: string, body: unknown): Promise { const url = `${this.baseUrl}${path}`; const res = await fetch(url, { @@ -297,6 +612,17 @@ export class AlphahumanMemoryClient { return this.handleResponse(res); } + private async delete(path: string): Promise { + const url = `${this.baseUrl}${path}`; + const res = await fetch(url, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${this.token}`, + }, + }); + return this.handleResponse(res); + } + private async handleResponse(res: Response): Promise { const text = await res.text(); let json: unknown; diff --git a/packages/sdk-typescript/test/client.test.ts b/packages/sdk-typescript/test/client.test.ts index b95c62b..50e691d 100644 --- a/packages/sdk-typescript/test/client.test.ts +++ b/packages/sdk-typescript/test/client.test.ts @@ -275,4 +275,38 @@ describe('AlphahumanMemoryClient', () => { ); }); }); + + describe('chatMemory', () => { + it('POSTs to /v1/memory/chat', async () => { + fetchMock.mockResolvedValueOnce({ + ok: true, + text: () => Promise.resolve(JSON.stringify({ success: true, data: { content: 'hello' } })), + }); + const client = new AlphahumanMemoryClient({ token, baseUrl }); + await client.chatMemory({ messages: [{ role: 'user', content: 'hi' }] }); + expect(fetchMock).toHaveBeenCalledWith( + `${baseUrl}/v1/memory/chat`, + expect.objectContaining({ + method: 'POST', + body: JSON.stringify({ messages: [{ role: 'user', content: 'hi' }] }), + }) + ); + }); + }); + + describe('listDocuments', () => { + it('GETs from /v1/memory/documents with query params', async () => { + fetchMock.mockResolvedValueOnce({ + ok: true, + text: () => Promise.resolve(JSON.stringify({ success: true, data: {} })), + }); + const client = new AlphahumanMemoryClient({ token, baseUrl }); + await client.listDocuments({ namespace: 'ns', limit: 10 }); + expect(fetchMock).toHaveBeenCalledWith( + `${baseUrl}/v1/memory/documents?namespace=ns&limit=10`, + expect.objectContaining({ method: 'GET' }) + ); + }); + }); }); +