@neo4j-labs/agent-memory 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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/middleware/vercel-ai.ts"],"names":[],"mappings":"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","file":"vercel-ai.js","sourcesContent":["/**\n * Vercel AI SDK middleware for automatic memory integration.\n *\n * The middleware automatically:\n * - Injects three-tier conversational context (reflections + observations +\n * recent messages) ahead of every model call when a `conversationId` is\n * supplied — falls back to flat history for bridge transports.\n * - Persists the user's input message before generation.\n * - Persists the assistant's response (and tool calls) after generation.\n * - Lazily creates a conversation on first call when the caller didn't\n * pre-create one (only available with RestTransport).\n *\n * @example\n * ```ts\n * import { generateText } from \"ai\";\n * import { MemoryClient } from \"@neo4j-labs/agent-memory\";\n * import { agentMemoryMiddleware } from \"@neo4j-labs/agent-memory/middleware/vercel-ai\";\n *\n * const client = new MemoryClient({\n * endpoint: \"https://memory.neo4jlabs.com/v1\",\n * apiKey: process.env.MEMORY_API_KEY!,\n * });\n *\n * const middleware = agentMemoryMiddleware(client, {\n * conversationId: \"conv-uuid\", // or sessionId for bridge transport\n * userId: \"alice@example.com\", // used if a conversation is created\n * includeContext: true,\n * });\n *\n * const result = await generateText({\n * model: yourModel,\n * experimental_middleware: middleware,\n * messages: [{ role: \"user\", content: \"Hello!\" }],\n * });\n * ```\n *\n * Compatible with the Vercel AI SDK v4+ `LanguageModelV1Middleware` shape.\n */\n\nimport type { MemoryClient } from \"../client.js\";\nimport { NotSupportedError } from \"../errors.js\";\nimport type { Message, MessageRole } from \"../types.js\";\n\nexport interface AgentMemoryMiddlewareOptions {\n /**\n * Conversation id (REST transport) or session id (bridge transport).\n * Can be a string or a function that returns one.\n */\n conversationId?: string | (() => string);\n\n /** @deprecated Use `conversationId`. Kept for backwards compatibility. */\n sessionId?: string | (() => string);\n\n /**\n * User id used when lazily creating a conversation. Only consulted if\n * `conversationId` is not supplied and the transport is REST.\n */\n userId?: string;\n\n /**\n * Include three-tier context (reflections + observations + recent messages).\n * If false, falls back to flat history. Default: true on REST, false on\n * bridge (where context endpoints aren't implemented).\n */\n includeContext?: boolean;\n\n /** Maximum messages to include from flat history (bridge fallback). */\n historyLimit?: number;\n\n /** Persist user input before generation. Default: true. */\n persistInput?: boolean;\n\n /** Persist assistant response after generation. Default: true. */\n persistResponses?: boolean;\n}\n\nexport interface AgentMemoryLanguageModelMiddleware {\n transformParams?: (options: { params: Record<string, unknown> }) => Promise<\n Record<string, unknown>\n >;\n wrapGenerate?: (options: {\n doGenerate: () => Promise<{ text?: string; [key: string]: unknown }>;\n }) => Promise<{ text?: string; [key: string]: unknown }>;\n}\n\nfunction resolve(value?: string | (() => string)): string | undefined {\n if (typeof value === \"function\") return value();\n return value;\n}\n\n/** Memory-augmented LanguageModelV1 middleware. */\nexport function agentMemoryMiddleware(\n client: MemoryClient,\n options?: AgentMemoryMiddlewareOptions,\n): AgentMemoryLanguageModelMiddleware {\n const persistResponses = options?.persistResponses ?? true;\n const persistInput = options?.persistInput ?? true;\n const includeContext = options?.includeContext ?? true;\n let resolvedId: string | undefined =\n resolve(options?.conversationId) ?? resolve(options?.sessionId);\n\n // Lazy-create a conversation on REST transports if none was supplied.\n async function ensureConversationId(): Promise<string> {\n if (resolvedId) return resolvedId;\n try {\n const conv = await client.shortTerm.createConversation({\n userId: options?.userId ?? \"anonymous\",\n });\n resolvedId = conv.id;\n return resolvedId;\n } catch (err) {\n if (err instanceof NotSupportedError) {\n // Bridge transport — synthesize a session ID\n resolvedId = `session-${cryptoRandom()}`;\n return resolvedId;\n }\n throw err;\n }\n }\n\n return {\n transformParams: async ({ params }) => {\n const id = await ensureConversationId();\n\n let historyMessages: Array<{ role: string; content: string }> = [];\n if (includeContext) {\n try {\n const ctx = await client.shortTerm.getContext(id);\n for (const r of ctx.reflections) {\n historyMessages.push({ role: \"system\", content: `[reflection] ${r.content}` });\n }\n for (const o of ctx.observations) {\n historyMessages.push({ role: \"system\", content: `[observation] ${o.content}` });\n }\n for (const m of ctx.recentMessages) {\n historyMessages.push({ role: m.role, content: m.content });\n }\n } catch (err) {\n if (!(err instanceof NotSupportedError)) {\n // Non-fatal — fall back to flat history below.\n }\n historyMessages = [];\n }\n }\n\n // Bridge fallback or empty REST context → use flat conversation history.\n if (historyMessages.length === 0) {\n try {\n const conv = await client.shortTerm.getConversation(id, {\n limit: options?.historyLimit,\n });\n historyMessages = conv.messages.map((msg: Message) => ({\n role: msg.role,\n content: msg.content,\n }));\n } catch {\n // No history — proceed without.\n }\n }\n\n // Best-effort: persist the user's input message.\n if (persistInput) {\n const incoming = (params[\"prompt\"] as Array<{ role: string; content: string }>) ?? [];\n const lastUser = [...incoming].reverse().find((m) => m.role === \"user\");\n if (lastUser) {\n try {\n await client.shortTerm.addMessage(id, lastUser.role as MessageRole, lastUser.content);\n } catch {\n // Non-fatal.\n }\n }\n }\n\n if (historyMessages.length === 0) return params;\n\n const existing = (params[\"prompt\"] as unknown[]) ?? [];\n return {\n ...params,\n prompt: [...historyMessages, ...existing],\n };\n },\n\n wrapGenerate: async ({ doGenerate }) => {\n const result = await doGenerate();\n if (persistResponses && result.text) {\n const id = await ensureConversationId();\n try {\n await client.shortTerm.addMessage(id, \"assistant\", result.text);\n } catch {\n // Non-fatal.\n }\n }\n return result;\n },\n };\n}\n\nfunction cryptoRandom(): string {\n // Every supported runtime (Node 20+, Bun, Deno, Workers, modern browsers)\n // exposes crypto.randomUUID. We fall back to crypto.getRandomValues with\n // base36 encoding for older or stripped-down environments — both APIs use\n // the platform CSPRNG. Math.random would be cryptographically insecure.\n if (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n return crypto.randomUUID();\n }\n if (typeof crypto !== \"undefined\" && typeof crypto.getRandomValues === \"function\") {\n const buf = new Uint8Array(16);\n crypto.getRandomValues(buf);\n return Array.from(buf, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n }\n throw new Error(\n \"Secure randomness is unavailable in this runtime; supply an explicit conversationId.\",\n );\n}\n"]}
@@ -0,0 +1,37 @@
1
+ import { T as Transport, L as Logger } from './index-qfRrdQNP.js';
2
+
3
+ /**
4
+ * BridgeTransport — TCK bridge protocol transport.
5
+ *
6
+ * Speaks the bridge wire format (POST {endpoint}/{snake_case_method}) used by
7
+ * conformance servers and the local reference adapter. Compatible with every
8
+ * fetch-capable runtime (Node 20+, Bun, Deno, Workers, Edge).
9
+ */
10
+
11
+ interface BridgeTransportOptions {
12
+ /** Base URL of the bridge endpoint (no trailing /v1). */
13
+ endpoint: string;
14
+ /** API key for Bearer auth. Optional for local bridge servers. */
15
+ apiKey?: string;
16
+ /** Request timeout in milliseconds. Default: 30000. */
17
+ timeout?: number;
18
+ /** Additional headers to include in every request. */
19
+ headers?: Record<string, string>;
20
+ /** Per-request logger. */
21
+ logger?: Logger;
22
+ }
23
+ declare class BridgeTransport implements Transport {
24
+ private readonly endpoint;
25
+ private readonly apiKey?;
26
+ private readonly timeout;
27
+ private readonly headers;
28
+ private readonly logger?;
29
+ constructor(options: BridgeTransportOptions);
30
+ connect(): Promise<void>;
31
+ close(): Promise<void>;
32
+ request<T>(method: string, params: Record<string, unknown>): Promise<T>;
33
+ private emit;
34
+ private buildHeaders;
35
+ }
36
+
37
+ export { BridgeTransport, type BridgeTransportOptions };
@@ -0,0 +1,4 @@
1
+ export { BridgeTransport } from './chunk-TGBKROHO.js';
2
+ import './chunk-ASQMU7YC.js';
3
+ //# sourceMappingURL=testing.js.map
4
+ //# sourceMappingURL=testing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"testing.js"}
package/package.json ADDED
@@ -0,0 +1,86 @@
1
+ {
2
+ "name": "@neo4j-labs/agent-memory",
3
+ "version": "0.3.0",
4
+ "description": "Neo4j Labs: TypeScript client for the Neo4j Agent Memory Service (NAMS)",
5
+ "type": "module",
6
+ "license": "Apache-2.0",
7
+ "author": "Neo4j Labs",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/neo4j-labs/agent-memory",
11
+ "directory": "typescript"
12
+ },
13
+ "exports": {
14
+ ".": {
15
+ "import": "./dist/index.js",
16
+ "types": "./dist/index.d.ts"
17
+ },
18
+ "./middleware/vercel-ai": {
19
+ "import": "./dist/middleware/vercel-ai.js",
20
+ "types": "./dist/middleware/vercel-ai.d.ts"
21
+ },
22
+ "./mcp": {
23
+ "import": "./dist/mcp/index.js",
24
+ "types": "./dist/mcp/index.d.ts"
25
+ },
26
+ "./integrations/langchain": {
27
+ "import": "./dist/integrations/langchain.js",
28
+ "types": "./dist/integrations/langchain.d.ts"
29
+ },
30
+ "./integrations/mastra": {
31
+ "import": "./dist/integrations/mastra.js",
32
+ "types": "./dist/integrations/mastra.d.ts"
33
+ },
34
+ "./integrations/strands": {
35
+ "import": "./dist/integrations/strands.js",
36
+ "types": "./dist/integrations/strands.d.ts"
37
+ },
38
+ "./testing": {
39
+ "import": "./dist/testing.js",
40
+ "types": "./dist/testing.d.ts"
41
+ }
42
+ },
43
+ "homepage": "https://neo4j.com/labs/agent-memory/sdks/typescript",
44
+ "main": "./dist/index.js",
45
+ "types": "./dist/index.d.ts",
46
+ "files": [
47
+ "dist",
48
+ "README.md",
49
+ "LICENSE",
50
+ "CHANGELOG.md"
51
+ ],
52
+ "scripts": {
53
+ "build": "npm run check:version && tsup",
54
+ "check:version": "node ./scripts/check-version-sync.mjs",
55
+ "dev": "tsup --watch",
56
+ "test": "vitest run test/unit test/integration",
57
+ "test:unit": "vitest run test/unit",
58
+ "test:integration": "vitest run test/integration",
59
+ "test:e2e": "vitest run test/e2e",
60
+ "test:all": "vitest run",
61
+ "test:watch": "vitest",
62
+ "test:tck": "RUN_TCK_BRIDGE=1 vitest run test/tck",
63
+ "tck:bronze": "RUN_TCK_BRIDGE=1 vitest run test/tck --grep Bronze",
64
+ "lint": "tsc --noEmit",
65
+ "docs:api": "typedoc",
66
+ "conformance:server": "tsx conformance/server.ts",
67
+ "prepublishOnly": "npm run build"
68
+ },
69
+ "devDependencies": {
70
+ "@ai-sdk/provider": "^3.0.10",
71
+ "@modelcontextprotocol/sdk": "^1.29.0",
72
+ "@opentelemetry/api": "^1.9.1",
73
+ "@strands-agents/sdk": "^1.2.0",
74
+ "@types/node": "^20.0.0",
75
+ "dotenv": "^17.4.2",
76
+ "msw": "^2.14.3",
77
+ "tsup": "^8.0.0",
78
+ "tsx": "^4.0.0",
79
+ "typedoc": "^0.26.0",
80
+ "typescript": "^5.5.0",
81
+ "vitest": "^2.0.0"
82
+ },
83
+ "engines": {
84
+ "node": ">=20.0.0"
85
+ }
86
+ }