Skip to content

GUM Node SDK

This page shows how to integrate GUM Memory from a Node.js backend with @steamory-agent-kit/gum: create Sessions, append conversation messages, retrieve Memory, and write user Actions.

Use the GUM API Key only from server-side code. Do not expose it in browsers, mobile apps, or public repositories.

Before you start

You need:

  • Node.js 18 or later.
  • A valid GUM API Key.
  • A server-side runtime, such as a Node.js API route, worker backend, Express service, or queue job.

For local testing, set the API key as an environment variable:

bash
export GUM_API_KEY="<your-gum-api-key>"

Install

bash
npm install @steamory-agent-kit/gum

The SDK ships ESM, CommonJS, and TypeScript declarations. Node.js 18+ can use the built-in fetch implementation.

Quickstart

The following example covers the shortest integration path: initialize the client, create a Session, write a few conversation messages, and retrieve relevant Memory.

ts
import { GumClient } from "@steamory-agent-kit/gum";

const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
});

const session = await gum.sessions.create({
  user_id: "user_123",
  title: "Team scheduling session",
});

await session.addMessages([
  {
    role: "user",
    content:
      "For team scheduling, use Berlin when I mention Europe and Toronto when I mention the Americas.",
  },
  {
    role: "assistant",
    content:
      "Got it. I will use Berlin for Europe scheduling and Toronto for Americas scheduling.",
  },
]);

const memory = await session.getMemory({
  query: "which city should be used for Europe team scheduling",
});

console.log(memory.data);

Checkpoint

After this code runs, you should have a Session object and a Memory result in memory.data. Use session.id as the stable identifier for adding future messages and retrieving future Memory.

Use GUM in an assistant turn

In a real agent or assistant system, use this flow:

  1. Receive the user input in your Node.js backend.
  2. Retrieve relevant Memory for the current session.id.
  3. Add that Memory to your model context.
  4. After the model replies, write the user message and assistant reply back to GUM.
ts
import { GumClient } from "@steamory-agent-kit/gum";

const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
});

type ModelInput = {
  userContent: string;
  recalledMemory: unknown;
};

async function generateAssistantReply(input: ModelInput): Promise<string> {
  // Replace this function with your OpenAI, Anthropic, Gemini, or local model call.
  return `I will use the recalled memory for: ${input.userContent}`;
}

export async function assistantTurn(params: {
  sessionId: string;
  userContent: string;
}) {
  const session = gum.sessions.fromId(params.sessionId);

  const memory = await session.getMemory({
    query: params.userContent,
    details: true,
  });

  const assistantReply = await generateAssistantReply({
    userContent: params.userContent,
    recalledMemory: memory.data,
  });

  await session.addMessages([
    { role: "user", content: params.userContent },
    { role: "assistant", content: assistantReply },
  ]);

  return {
    reply: assistantReply,
    memory: memory.data,
  };
}

Checkpoint

In production, store session.id when a new conversation is created. Later requests can restore the local Session handle with gum.sessions.fromId(sessionId); this does not make a network request.

Client configuration

By default, only apiKey is required. You do not need to configure host when using the default GUM service.

ts
import { GumClient } from "@steamory-agent-kit/gum";

const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
});

Pass additional options when you need a custom deployment or timeout behavior:

ts
const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
  host: "gum.asix.inc",
  timeoutMs: 30_000,
});
OptionTypeDefaultDescription
apiKeystringRequiredGUM API Key. The SDK sends Authorization: Api-Key <apiKey>. Values that already start with Api-Key are not prefixed again.
hoststringgum.asix.incGUM service host. Plain host values are normalized to HTTPS, explicit http:// and https:// URLs are preserved, and a trailing / is removed.
timeoutMsnumber30000Default request timeout in milliseconds. Set to 0 to disable the SDK timeout.
fetchFetchLikeglobalThis.fetchFetch-compatible implementation for tests, proxies, custom runtimes, or observability wrappers.

Health check

gum.health(options?) checks the GUM service health endpoint. Use it in startup checks, deployment verification, or monitoring probes.

ts
const health = await gum.health();

console.log(health);

Parameters:

NameTypeRequiredDescription
optionsRequestOptionsNoPer-request options. Use it to override timeout, abort signal, and headers.

Sessions

A Session is the GUM object that holds one user conversation and its Memory retrieval context. Prefer the methods on the Session handle. Use lower-level resource methods only when passing raw Session IDs is more convenient for your application.

Create a Session

gum.sessions.create(input, options?) creates a Session and returns a Session object. user_id is required by the current GUM API.

ts
const session = await gum.sessions.create({
  user_id: "user_123",
  title: "Support chat",
  metadata: {
    source: "web-chat",
    locale: "en-US",
  },
});

console.log(session.id);
console.log(session.rawResponse);

Parameters:

NameTypeRequiredDescription
inputSessionCreateRequestYesRequest body for creating a Session.
input.user_idstringYesUser ID from your application. GUM uses it to associate the Session with user Memory.
input.titlestring | nullNoSession title, useful for storing a conversation topic or source label.
input.metadataRecord<string, unknown> | nullNoCustom metadata such as channel, locale, product area, or business trace information.
optionsRequestOptionsNoPer-request options.

session.rawResponse keeps the original response envelope returned by GUM when the Session was created. If GUM returns a successful response without data.session_id, the SDK throws a regular Error with the message Gum API did not return data.session_id.

Restore a Session handle

gum.sessions.fromId(sessionId) creates a local Session handle from an existing Session ID without making a network request.

ts
const session = gum.sessions.fromId("session_123");

await session.addMessage({
  role: "user",
  content: "Continue with the city preference from earlier.",
});

Parameters:

NameTypeRequiredDescription
sessionIdstringYesExisting Session ID that was created by GUM and stored in your application.

Add messages

session.addMessage(message, options?) writes one message.

ts
await session.addMessage({
  role: "user",
  content: "For Europe planning, keep Berlin as the default city.",
  metadata: {
    channel: "chat",
  },
});

Parameters:

NameTypeRequiredDescription
messageMessageYesOne message to write to the current Session.
message.rolestringYesMessage role, such as user, assistant, system, or a custom role from your application.
message.contentstringYesMessage text. GUM uses it to build and retrieve Memory.
message.idstring | nullNoMessage ID from your application. Use it to connect GUM writes with your message table, logs, or traces.
message.metadataRecord<string, unknown>NoMessage-level metadata such as channel, model name, locale, or business tags.
message.timestampstring | Date | nullNoTime when the message happened. Date values are serialized to ISO strings.
message.created_atstring | Date | nullNoTime when the message was created. Use it when this differs from the event timestamp.
message.statuspending | chunked | processed | failedNoMessage processing status.
optionsRequestOptionsNoPer-request options.

session.addMessages(input, options?) writes multiple messages. input can be either a message array or an object with a messages field.

ts
await session.addMessages([
  {
    role: "user",
    content: "Use Toronto for Americas planning.",
  },
  {
    role: "assistant",
    content: "Understood. I will use Toronto for Americas planning.",
  },
]);

await session.addMessages({
  messages: [
    {
      role: "user",
      content: "Keep those defaults for future scheduling tasks.",
      timestamp: new Date(),
    },
  ],
});

Parameters:

NameTypeRequiredDescription
inputMessage[] | AddMessagesRequestYesMessage collection to write. Array input is wrapped by the SDK as { messages }.
input.user_idstring | nullNoOptional user ID. Usually the Session is already bound to user_id when created, so this does not need to be repeated.
input.messagesMessage[]YesMessages to write to the current Session. When using array shorthand, the SDK creates this field.
optionsRequestOptionsNoPer-request options.

Message Date values are serialized to ISO strings. undefined fields are removed from request bodies.

Lower-level Session methods

If you only want to pass the Session ID, call the resource methods directly.

ts
await gum.sessions.addMessages("session_123", [
  {
    role: "user",
    content: "Draft the next Europe team agenda.",
  },
]);

const memory = await gum.sessions.getMemory("session_123", {
  query: "which city should be used for Europe planning",
});

gum.sessions.addMessages(sessionId, input, options?) parameters:

NameTypeRequiredDescription
sessionIdstringYesSession ID to write messages to. The SDK safely encodes this value in the URL.
inputMessage[] | AddMessagesRequestYesMessage collection to write.
optionsRequestOptionsNoPer-request options.

gum.sessions.getMemory(sessionId, params?, options?) parameters:

NameTypeRequiredDescription
sessionIdstringYesSession ID to retrieve Memory from. The SDK safely encodes this value in the URL.
paramsGetSessionMemoryParamsNoMemory retrieval parameters. Omit it to request default Memory for the current Session.
optionsRequestOptionsNoPer-request options.

Memory recall and recall_config

session.getMemory(params?, options?) retrieves Memory for the current Session. Use query to focus retrieval and details to request richer response data.

ts
const memory = await session.getMemory({
  query: "which city should be used for Europe or Americas planning",
  details: true,
});

Parameters:

NameTypeRequiredDescription
paramsGetSessionMemoryParamsNoMemory retrieval parameters. Omit it to use GUM's default retrieval strategy for the current Session.
params.querystringNoQuery text for retrieval. Prefer the current user intent instead of the full prompt.
params.detailsbooleanNoRequests richer Memory response data. Exact fields depend on the GUM API response.
params.recall_configRecallConfig | nullNoRecall configuration. When present, the SDK uses the POST context request; null sends an explicit empty configuration.
optionsRequestOptionsNoPer-request options.

By default, the SDK uses the GET context request. When recall_config is present, the SDK uses the POST context request and sends the recall settings in the JSON body.

ts
const memory = await session.getMemory({
  query: "which city should be used for the user's scheduling request",
  details: true,
  recall_config: {
    message_recent_limit: 20,
    message_semantic_top_k: 8,
    query_router: "single_hop_parallel",
    enable_long_term_recall: false,
  },
});

Common recall_config fields:

FieldTypePurpose
message_recent_limitnumberControls how many recent messages can be recalled.
message_semantic_top_knumberControls how many semantically matched messages can be recalled.
message_semantic_min_scorenumberSets the minimum semantic score for message recall.
query_router"single_hop_direct" | "single_hop_parallel" | "multi_hop_chain"Selects the query routing strategy.
enable_long_term_recallbooleanControls whether long-term Memory recall is enabled.
enable_long_term_rerankbooleanControls whether long-term Memory reranking is enabled.

User Actions

User Actions record important product behavior, such as page views, button clicks, tool calls, or task state changes. They are useful for building Action Memory so an Agent can understand behavioral context.

ts
await gum.userActions.create({
  user_id: "user_123",
  timestamp: new Date(),
  content: "User opened the Europe team scheduling page",
  session_id: "session_123",
  event_type: "page_view",
  page: "team_scheduling",
  anchors: {
    region: "Europe",
    city: "Berlin",
  },
  metadata: {
    source: "assistant-api",
  },
});

gum.userActions.create(input, options?) parameters:

NameTypeRequiredDescription
inputActionLogInputYesRequest body for a user Action event.
input.user_idstringYesUser ID from your application that triggered this Action.
input.timestampstring | DateYesTime when the Action happened. Date values are serialized to ISO strings.
input.contentstringYesNatural-language description of the Action. Prefer a clear statement of what the user did.
input.session_idstring | nullNoRelated Session ID. Use it to connect behavior with conversation context.
input.device_idstring | nullNoDevice ID, useful for multi-device behavior analysis.
input.appstring | nullNoApplication or product area name.
input.platformstring | nullNoPlatform such as web, ios, android, or server.
input.event_typestring | nullNoEvent type such as page_view, click, or tool_call.
input.pagestring | nullNoPage, route, or feature entry point.
input.anchorsRecord<string, string> | nullNoSearchable anchors such as region, city, or document_id.
input.metadataRecord<string, unknown> | nullNoCustom metadata.
input.entitiesstring[] | nullNoEntity names or IDs related to the Action.
optionsRequestOptionsNoPer-request options.

timestamp can be an ISO string or a Date. If you pass a Date, the SDK serializes it automatically.

Runtime behavior

Request options

Every SDK method accepts request options as its final argument. Use them to override timeout, abort signal, or headers for one request.

ts
const controller = new AbortController();

const memory = await session.getMemory(
  {
    query: "which scheduling city should be used",
  },
  {
    timeoutMs: 5_000,
    signal: controller.signal,
    headers: {
      "X-Request-Id": "request_123",
    },
  },
);
OptionTypeDescription
timeoutMsnumberOverrides the timeout for one request.
signalAbortSignalExternal abort signal.
headersHeadersInitAdditional request headers.

Response envelope

Except for gum.sessions.create(), which returns a Session object, resource methods return the GUM response envelope.

ts
type GumEnvelope<T = unknown> = {
  data?: T;
  success?: boolean;
  message?: string;
  error?: unknown;
  [key: string]: unknown;
};

For example:

  • session.getMemory() returns Promise<GumEnvelope<SessionMemory>>.
  • session.addMessages() returns the GUM response envelope.
  • gum.userActions.create() returns Promise<GumEnvelope<CreateActionResponse>>.

Serialization

Before sending a JSON body, the SDK applies lightweight serialization:

  • Date values become ISO strings.
  • undefined fields are removed from objects and arrays.
  • null is preserved, which is useful when you need to send an explicit empty value.

Error handling

The SDK exposes three primary error types:

ts
import {
  GumApiError,
  GumConnectionError,
  GumTimeoutError,
} from "@steamory-agent-kit/gum";

try {
  await session.getMemory({
    query: "which scheduling city should be used",
  });
} catch (error) {
  if (error instanceof GumApiError) {
    console.error(error.status, error.detail, error.body);
  } else if (error instanceof GumTimeoutError) {
    console.error(`Request timed out after ${error.timeoutMs}ms`);
  } else if (error instanceof GumConnectionError) {
    console.error("Network or fetch failure", error.cause);
  } else {
    throw error;
  }
}
ErrorWhen it is thrown
GumApiErrorGUM returns a non-2xx response. Includes status, statusText, headers, body, and detail.
GumConnectionErrorThe underlying fetch request fails before a response is received.
GumTimeoutErrorA request is aborted by the SDK timeout or an external AbortSignal. Extends GumConnectionError.

TypeScript reference

Common types are exported from the package root:

ts
import type {
  ActionLogInput,
  AddMessagesRequest,
  CreateActionResponse,
  GumClientOptions,
  GumEnvelope,
  Message,
  RecallConfig,
  RequestOptions,
  SessionMemory,
  SessionCreateRequest,
} from "@steamory-agent-kit/gum";

import { GumClient, Session } from "@steamory-agent-kit/gum";

Core type reference:

ts
type QueryRouter =
  | "single_hop_direct"
  | "single_hop_parallel"
  | "multi_hop_chain";

interface SessionCreateRequest {
  user_id: string;
  title?: string | null;
  metadata?: Record<string, unknown> | null;
}

interface Message {
  role: string;
  content: string;
  id?: string | null;
  metadata?: Record<string, unknown>;
  timestamp?: string | Date | null;
  created_at?: string | Date | null;
  status?: "pending" | "chunked" | "processed" | "failed";
}

Troubleshooting

apiKey must not be empty

apiKey is an empty string or contains only whitespace. Confirm that GUM_API_KEY is available in the server-side runtime and that runtime-only code is not being executed unexpectedly during a build step.

ts
const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
});

401 or 403

Check that the API Key is correct, has permission to access the target GUM service, and that requests are going to the expected host. The SDK adds the Api-Key prefix automatically, so you do not need to concatenate it yourself.

Request timeout

The default timeout is 30 seconds. You can adjust it at the client level or per request.

ts
const gum = new GumClient({
  apiKey: process.env.GUM_API_KEY!,
  timeoutMs: 60_000,
});

Empty Memory result

First confirm that messages were written to the same Session. Then use a query that describes the user's intent. Add recall_config only when you need more control over retrieval behavior.

Next step

Continue with GUM Overview to understand GUM's role as the Memory infrastructure layer in SAK, or read Integration Patterns to choose a production integration pattern.

Agent infrastructure for identity, memory, and web action.