diff --git a/README.md b/README.md index 9e77d73..37e38d0 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,27 @@ node ./scripts/memory-backup.mjs restore --in backup.json --out restored.json These operations are also available programmatically through `backup-restore.mjs`. +## Vector Search & Embeddings OAuth + +Memact Memory supports retrieving memories using hybrid semantic search. To securely integrate with enterprise embedding providers (like Azure OpenAI) and restrict search access, Memory implements an OAuth 2.0 Client Credentials flow. + +### Inbound Authorization +When querying via the API or CLI, clients must provide a JWT containing either the `vector:search` or `vector:read` scope to access semantic capabilities. +```sh +node ./src/cli.mjs --query "startup execution" \ + --access-token "header.eyJzY29wZSI6InZlY3RvcjpzZWFyY2gifQ.sig" +``` + +### Outbound Authentication +You can configure Memory to acquire its own Bearer tokens dynamically to invoke external embedding models, eliminating the need to hardcode static API keys. +```sh +node ./src/cli.mjs --query "startup execution" \ + --oauth-client-id "client_123" \ + --oauth-client-secret "secret_456" \ + --oauth-endpoint "https://auth.enterprise.com/token" \ + --embedding-provider "azure" +``` + ## Development To install and run tests: diff --git a/src/cli.mjs b/src/cli.mjs index f3d4eb9..ffd7f17 100644 --- a/src/cli.mjs +++ b/src/cli.mjs @@ -1,6 +1,7 @@ #!/usr/bin/env node import { readFile } from "node:fs/promises"; import { buildMemoryStore, buildRagContext, formatMemoryReport, retrieveMemories } from "./engine.mjs"; +import { createEmbeddingService } from "./embeddings.mjs"; function argValue(name, fallback = "") { const index = process.argv.indexOf(name); @@ -19,6 +20,12 @@ const query = argValue("--query"); const format = argValue("--format", "report"); const graphLimit = Number(argValue("--limit", "24")) || 24; +const accessToken = argValue("--access-token"); +const oauthClientId = argValue("--oauth-client-id"); +const oauthClientSecret = argValue("--oauth-client-secret"); +const oauthEndpoint = argValue("--oauth-endpoint"); +const provider = argValue("--embedding-provider"); + if (!inferencePath && !schemaPath) { console.error("Usage: memact-memory --inference inference.json --schema schema.json [--memory memory.json] [--query thought] [--format report|json|graph|mermaid|dot]"); process.exit(1); @@ -155,8 +162,25 @@ function formatDot(memoryStore, limit = 24) { } if (query) { - const rag = buildRagContext(query, memoryStore); - const result = retrieveMemories(query, memoryStore); + const options = {}; + if (accessToken) { + options.accessToken = accessToken; + } + + if (oauthClientId && oauthClientSecret && oauthEndpoint) { + const service = createEmbeddingService({ + provider: provider || "openai", + oauth: { + clientId: oauthClientId, + clientSecret: oauthClientSecret, + tokenEndpoint: oauthEndpoint + } + }); + options.queryEmbedding = await service.getEmbedding(query); + } + + const rag = buildRagContext(query, memoryStore, options); + const result = retrieveMemories(query, memoryStore, options); if (format === "json") { console.log(JSON.stringify({ query, rag, memories: result }, null, 2)); } else {