Enable request logging

The TypeScript client emits a typed event stream around every HTTP exchange via the logger constructor option. Hook this into your favourite logger (Pino, Winston, console) for tracing, request-id correlation, and ops dashboards.

Prerequisites: a configured MemoryClient and an application logger.

Procedure

  1. Pass a logger callback when constructing the client.

  2. Make a supported read and inspect the emitted event fields below.

  3. Redact query values and service error text before exporting logs; retain a request id when supplied.

Basic usage

import { MemoryClient, type LogEvent } from "@neo4j-labs/agent-memory";

const client = new MemoryClient({
  logger: (event: LogEvent) => {
    console.log(JSON.stringify(event));
  },
});

You’ll see two events per successful call:

{ "kind": "request", "method": "create_conversation", "url": "...", "httpMethod": "POST" }
{ "kind": "response", "method": "create_conversation", "url": "...", "status": 200,
  "requestId": "req-abc", "durationMs": 142 }

Recognized HTTP failures emit request then error:

{ "kind": "request", "method": "create_conversation", "url": "...", "httpMethod": "POST" }
{ "kind": "error", "method": "create_conversation", "url": "...", "status": 500,
  "requestId": "req-abc", "durationMs": 87, "message": "..." }

Event shape

type LogEvent =
  | { kind: "request"; method: string; url: string; httpMethod?: string }
  | { kind: "response"; method: string; url: string; status: number;
      requestId?: string; durationMs: number }
  | { kind: "error"; method: string; url: string; status?: number;
      requestId?: string; durationMs: number; message: string };

method is the snake_case bridge method name (create_conversation, search_entities, record_step, …). httpMethod is the HTTP verb (POST, GET, …).

Bodies are never logged by default

The logger does not receive separate request or response body fields. URLs can contain search query values, and error messages can include server-provided text. Apply redaction before exporting events; absence of body fields is not a guarantee that events contain no sensitive data. If you need bodies during development, log them yourself by wrapping the call:

const msg = await client.shortTerm.addMessage(conv.id, "user", "hi");
console.debug("addMessage result:", msg);

Logger exceptions are swallowed

If your logger throws, the SDK catches the error and continues. This means a misbehaving logger can’t take down your application — but it also means logging is best-effort. Wrap calls into your structured logger in your own try/catch if you care.

User-Agent customization

The client sends a default User-Agent like @neo4j-labs/agent-memory/0.5.0 (node/22.5.0; darwin). To override, pass your own:

new MemoryClient({
  headers: { "User-Agent": "my-app/2.1 (CI runner)" },
});

Wrapping SDKs should append their own identifier (e.g., @neo4j-labs/agent-memory/0.5.0 my-wrapper/1.0) so server-side metrics can break the population down.

Request-id correlation

SDK errors built from a response may carry error.requestId. It is absent when the service supplied no recognized header or no response was captured. Pre-request validation/unsupported operations do not emit an HTTP event pair; raw aborts, parsing or token-provider failures may also lack an error event. See handle errors.

Verify the integration

Make one successful read and inspect its request/response pair. With an offline HTTP stub returning 500, check the request/error pair and optional request id. Also test a client-side validation failure: it need not emit HTTP events. The SDK’s observability and docs-contract integration tests cover these contracts without sending data to an external logging service.